From 90f07ebe81ae29b6670b1e315fdc55e13e62fdb0 Mon Sep 17 00:00:00 2001 From: Carsten Piepel Date: Wed, 2 Aug 2023 14:38:01 -0700 Subject: [PATCH 01/11] Forking aws-samples/aws-lambda-elixir-runtime. --- .DS_Store | Bin 0 -> 6148 bytes elixir_runtime/.DS_Store | Bin 0 -> 6148 bytes elixir_runtime/config/config.exs | 4 +- elixir_runtime/lib/.DS_Store | Bin 0 -> 6148 bytes .../elixir_runtime/lambda_service_client.ex | 14 +-- .../lib/elixir_runtime/monitor/error.ex | 8 +- .../lib/elixir_runtime/monitor/state.ex | 4 +- elixir_runtime/lib/mix/tasks/bootstrap.ex | 7 +- elixir_runtime/lib/mix/tasks/build.ex | 66 +++++++++++++ .../lib/mix/tasks/gen_lambda_release.ex | 56 ----------- elixir_runtime/lib/mix/tasks/zip.ex | 19 +++- elixir_runtime/mix.exs | 14 +-- elixir_runtime/priv/.DS_Store | Bin 0 -> 6148 bytes elixir_runtime/priv/docker/Dockerfile.build | 87 ++++++++++++++++++ examples/.DS_Store | Bin 0 -> 6148 bytes examples/hello_world/.DS_Store | Bin 0 -> 6148 bytes examples/hello_world/config/config.exs | 2 +- examples/hello_world/config/runtime.exs | 11 +++ examples/hello_world/mix.exs | 16 +++- examples/hello_world/rel/config.exs | 34 ------- examples/hello_world/rel/env.bat.eex | 8 ++ examples/hello_world/rel/env.sh.eex | 20 ++++ examples/hello_world/rel/remote.vm.args.eex | 8 ++ examples/hello_world/rel/vm.args.eex | 16 ++++ examples/hello_world/response.json | 1 + 25 files changed, 270 insertions(+), 125 deletions(-) create mode 100644 .DS_Store create mode 100644 elixir_runtime/.DS_Store create mode 100644 elixir_runtime/lib/.DS_Store create mode 100644 elixir_runtime/lib/mix/tasks/build.ex delete mode 100644 elixir_runtime/lib/mix/tasks/gen_lambda_release.ex create mode 100644 elixir_runtime/priv/.DS_Store create mode 100644 elixir_runtime/priv/docker/Dockerfile.build create mode 100644 examples/.DS_Store create mode 100644 examples/hello_world/.DS_Store create mode 100644 examples/hello_world/config/runtime.exs delete mode 100644 examples/hello_world/rel/config.exs create mode 100644 examples/hello_world/rel/env.bat.eex create mode 100644 examples/hello_world/rel/env.sh.eex create mode 100644 examples/hello_world/rel/remote.vm.args.eex create mode 100644 examples/hello_world/rel/vm.args.eex create mode 100644 examples/hello_world/response.json diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9c2e5e53ef04d52e428cf1d24bf53e3b7d897648 GIT binary patch literal 6148 zcmeHKQES^U5I&{ps!&?;u+csW_8M49OQH0|WZfUAOZ%{m%%06=>RKUonnDQpb^Am6 zC;L77PEuM*wmp`0+`;KPo$h4mvyps6q(-ysfT&MI8p_z|q4|yQIP02pf~N~qZjOSc zG=|QoT8kFPzsLZ;yIsnuq=N3C5AUx*?}qZM{#>Tkmb`e4z&lFdo**HoI-S>(w6rP4 zex#GKsGH&Nr|N8UH(zY&ExoNj#$W9`ZjxqJkCN$o?p0~G13ckZw+ty$Ad>c=z(pF!PxSDh|nV>Kr3FsB- zURkCvAPhVm1AIOhC}R|`_2`ZcG_C{y@^7RQ*j!6+jtLkAY&~KGqI@dQr>an5D4!0$ z32{-t)}v1+6^aiPo~%NJqTJIlzj5KDB9GDv1H!;#1~z=R&-eekKiB_{lcXmM2m}8W z1FCx#pN+7kaJQ~)j_+Cn{RCy2ZH0qaA4z*)K}$Qd75V=CBz)TjnkMBXlGZe z+2y7Pl&TH!;kUO)%cDC8R{pKI+ zh~UR}5a-LJfE17dQa}nwfh#CbHFa@+g|l>o6p#Y9r2zjA4NmNZV`BU|FhmOg{CV$V z9=!yxA(h--I3^+j^P~ck>eXU+(h+Z!*9*tQq?^ahIHzv*>QFpxN4!P4c~8_R1*E{a z0<&B$S^uBlfAs(7B(0=?6u2n`e7=5OukcA#TPGjKTHD|+aOQl$X_yBELzH7+lw&Md ejvpc^^BU*a?}cMx&=C(hP>%uXB9j9Dt-uMTyBD(n literal 0 HcmV?d00001 diff --git a/elixir_runtime/config/config.exs b/elixir_runtime/config/config.exs index a845745..a0f0d89 100644 --- a/elixir_runtime/config/config.exs +++ b/elixir_runtime/config/config.exs @@ -1,7 +1,7 @@ # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 -use Mix.Config +import Config config :logger, :console, @@ -9,4 +9,4 @@ config :logger, metadata: [:module, :function, :line] # Uncomment to enable environment-specific configuration -# import_config "#{Mix.env()}.exs" +# import_config "#{config_env()}.exs" diff --git a/elixir_runtime/lib/.DS_Store b/elixir_runtime/lib/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..24337ec4331b2a81873de23e6a71eaf932ff4ba2 GIT binary patch literal 6148 zcmeHK%Sr=55Ukc50)ph|ael!+7()C4KS0ssAgl(|K#qIzyZkh(9|+6Fg9k5C4c#@< z+qJ{gVS5{Ztqx%qSVnVnU}h;+W=39q=LAMi4(KAmvxC3YCdJx=)V z+&yEreR~`p_WR*9U0Eq01*Cu!kOETRmkN0Ar7bTK6{Ua_kOJQd`1hgF9ed%J7@rP? z7y*b2ro*_7S%TO+LF|QNA~Q5gDlw^6BZeiN`Brtka7;`(tcDM(ldUEci_`i37Ui&> zs3--bz*K?r+^)R;-_U=U|EDDFq<|FoR|?o-bGupdO4VCum-AlR==XH5`J}sX9TbLW l$HZvI+;}^_ilVG*zUK2@I3@<2`JfZ^GvK<&q`+S*@C7SO7i|Cl literal 0 HcmV?d00001 diff --git a/elixir_runtime/lib/elixir_runtime/lambda_service_client.ex b/elixir_runtime/lib/elixir_runtime/lambda_service_client.ex index 1e6b9c3..5037e53 100644 --- a/elixir_runtime/lib/elixir_runtime/lambda_service_client.ex +++ b/elixir_runtime/lib/elixir_runtime/lambda_service_client.ex @@ -23,17 +23,17 @@ defmodule ElixirRuntime.LambdaServiceClient do ) :: no_return def invocation_error(err_msg, id) do url = - 'http://#{service_endpoint()}/2018-06-01/runtime/invocation/#{id}/error' + ~c"http://#{service_endpoint()}/2018-06-01/runtime/invocation/#{id}/error" - request = {url, [], 'text/plain', err_msg} + request = {url, [], ~c"text/plain", err_msg} {:ok, _response} = :httpc.request(:post, request, [], []) end @impl true @spec init_error(Monitor.Client.error()) :: no_return def init_error(err_msg) do - url = 'http://#{service_endpoint()}/2018-06-01/runtime/init/error' - request = {url, [], 'text/plain', err_msg} + url = ~c"http://#{service_endpoint()}/2018-06-01/runtime/init/error" + request = {url, [], ~c"text/plain", err_msg} {:ok, _response} = :httpc.request(:post, request, [], []) end @@ -44,16 +44,16 @@ defmodule ElixirRuntime.LambdaServiceClient do ) :: no_return def complete_invocation(id, response) do url = - 'http://#{service_endpoint()}/2018-06-01/runtime/invocation/#{id}/response' + ~c"http://#{service_endpoint()}/2018-06-01/runtime/invocation/#{id}/response" - request = {url, [], 'text/plain', response} + request = {url, [], ~c"text/plain", response} {:ok, _response} = :httpc.request(:post, request, [], []) end @impl true @spec next_invocation() :: Runtime.Client.invocation() def next_invocation do - url = 'http://#{service_endpoint()}/2018-06-01/runtime/invocation/next' + url = ~c"http://#{service_endpoint()}/2018-06-01/runtime/invocation/next" response = :httpc.request(:get, {url, []}, [], []) Logger.debug("Http get from #{url} was #{Kernel.inspect(response)}") parse(response) diff --git a/elixir_runtime/lib/elixir_runtime/monitor/error.ex b/elixir_runtime/lib/elixir_runtime/monitor/error.ex index b71089f..7ff5afd 100644 --- a/elixir_runtime/lib/elixir_runtime/monitor/error.ex +++ b/elixir_runtime/lib/elixir_runtime/monitor/error.ex @@ -23,15 +23,15 @@ defmodule ElixirRuntime.Monitor.Error do stackTrace: list } - @doc "Build an Error from a structured process-exit reason" - @spec from_exit_reason(error_type, {atom(), list()}) :: error + @doc "Build an Error from a process-exit reason" + @spec from_exit_reason(error_type, term) :: error + def from_exit_reason(error_type, reason) + def from_exit_reason(error_type, _reason = {error, stacktrace}) do exception = Exception.normalize(:error, error, stacktrace) build_error(error_name(error_type, exception), exception, stacktrace) end - @doc "Build an Error from an unknown process-exit reason" - @spec from_exit_reason(error_type, term) :: error def from_exit_reason(error_type, reason) do exception = Exception.normalize(:error, {"unexpected exit", reason}) build_error(error_name(error_type, exception), exception, []) diff --git a/elixir_runtime/lib/elixir_runtime/monitor/state.ex b/elixir_runtime/lib/elixir_runtime/monitor/state.ex index af135a7..3d61112 100644 --- a/elixir_runtime/lib/elixir_runtime/monitor/state.ex +++ b/elixir_runtime/lib/elixir_runtime/monitor/state.ex @@ -22,14 +22,14 @@ defmodule ElixirRuntime.Monitor.State do @doc "report an error before an invocation was started" @spec error(monitor_state, term()) :: no_return + def error(monitor_state, reason) + def error({:not_started, client}, reason) do Monitor.Error.from_exit_reason(:runtime, reason) |> Poison.encode!() |> client.init_error() end - @doc "report an error before an invocation was started" - @spec error(monitor_state, term()) :: no_return def error({:in_progress, id, client}, reason) do Monitor.Error.from_exit_reason(:function, reason) |> Poison.encode!() diff --git a/elixir_runtime/lib/mix/tasks/bootstrap.ex b/elixir_runtime/lib/mix/tasks/bootstrap.ex index 736589b..a9a3a4b 100644 --- a/elixir_runtime/lib/mix/tasks/bootstrap.ex +++ b/elixir_runtime/lib/mix/tasks/bootstrap.ex @@ -27,7 +27,7 @@ defmodule Mix.Tasks.Bootstrap do # The bootstrap script contents defp bootstrap(app) when is_binary(app) do """ - \#!/bin/bash + \#!/bin/sh set -x @@ -37,12 +37,9 @@ defmodule Mix.Tasks.Bootstrap do HOME=/tmp export HOME - \# So that distillery doesn't try to write any files - export RELEASE_READ_ONLY=true - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$BASE/lib/#{@runtime_libs} - $EXE foreground + $EXE start """ end end diff --git a/elixir_runtime/lib/mix/tasks/build.ex b/elixir_runtime/lib/mix/tasks/build.ex new file mode 100644 index 0000000..0ab931b --- /dev/null +++ b/elixir_runtime/lib/mix/tasks/build.ex @@ -0,0 +1,66 @@ +defmodule Mix.Tasks.Build do + use Mix.Task + + @shortdoc "Uses Docker to build a release zip for deployment to Lambda" + + @moduledoc """ + Uses Docker to build a release zip for deployment to Lambda. + ``` + mix build + ``` + + ## Examples + + ``` + ❯ mix build + Building elixir_lambda_example version 0.1.0 + . . . + Lambda release built + Artifact: _build/dev/rel/elixir_lambda_example/lambda.dev.zip + ``` + """ + + def run(_args) do + version = Mix.Project.config()[:version] + app = app_name() + env = Mix.env() + dockerfile = Path.expand("#{__DIR__}/../../../priv/docker/Dockerfile.build") + image = "#{app}:#{version}_#{env}" + container = "#{app}_#{version}_#{env}" + release_dir = "_build/#{env}/rel/#{app}" + zipfile = "/examples/#{app}/_build/#{env}/rel/#{app}_lambda.zip" + + Mix.shell().info("Building #{app} version #{version} #{env} release") + File.mkdir_p(release_dir) + + commands = [ + "docker rm #{container} > /dev/null 2>&1 || true", + "docker build --build-arg MIX_ENV=#{env} -t #{image} -f #{dockerfile} ../../", + "docker run --name #{container} -d -i -t #{image} /bin/sh", + "docker cp #{container}:/workspace/#{zipfile} #{app}_lambda.zip", + "docker kill #{container}", + "docker rm #{container}" + ] + + Enum.each(commands, fn command -> + Mix.shell().cmd(command) + |> case do + 0 -> + :ok + + status -> + Mix.shell().error("Build failed") + Mix.raise("Exit status: #{inspect(status)}") + end + end) + + Mix.shell().info("Lambda release built") + Mix.shell().info("Artifact: #{release_dir}/lambda.#{env}.zip") + end + + defp app_name() do + Mix.Project.config() + |> Keyword.fetch!(:app) + |> to_string + end +end diff --git a/elixir_runtime/lib/mix/tasks/gen_lambda_release.ex b/elixir_runtime/lib/mix/tasks/gen_lambda_release.ex deleted file mode 100644 index a11a911..0000000 --- a/elixir_runtime/lib/mix/tasks/gen_lambda_release.ex +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: MIT-0 - -defmodule Mix.Tasks.GenLambdaRelease do - @moduledoc """ - Generate a distillery release configuration file for lambda release builds. - """ - - use Mix.Task - - @shortdoc "Generate a distillery release for AWS Lambda" - def run(_) do - name = - Mix.Project.config() - |> Keyword.fetch!(:app) - |> to_string - - Mix.Generator.create_file("rel/config.exs", distillery_config(name)) - end - - defp distillery_config(app) do - """ - ~w(rel plugins *.exs) - |> Path.join() - |> Path.wildcard() - |> Enum.map(&Code.eval_file(&1)) - - use Mix.Releases.Config, - default_release: :#{app}, - default_environment: :lambda - - environment :lambda do - set include_erts: true - set include_src: false - set cookie: :test - set include_system_libs: true - - \# Distillery forces the ERTS into 'distributed' mode which will - \# attempt to connect to EPMD. This is not supported behavior in the - \# AWS Lambda runtime because our process isn't allowed to connect to - \# other ports on this host. - \# - \# So '-start_epmd false' is set so the ERTS doesn't try to start EPMD. - \# And '-epmd_module' is set to use a no-op implementation of EPMD - set erl_opts: "-start_epmd false -epmd_module Elixir.EPMD.StubClient" - end - - release :#{app} do - set version: current_version(:#{app}) - set applications: [ - :runtime_tools, :aws_lambda_elixir_runtime - ] - end - """ - end -end diff --git a/elixir_runtime/lib/mix/tasks/zip.ex b/elixir_runtime/lib/mix/tasks/zip.ex index b03e414..9b7ae82 100644 --- a/elixir_runtime/lib/mix/tasks/zip.ex +++ b/elixir_runtime/lib/mix/tasks/zip.ex @@ -6,9 +6,18 @@ defmodule Mix.Tasks.Zip do @shortdoc "zip the contents of the current release" def run(_) do - path = release_path(app_name()) + app = app_name() + version = app_version() + env = Mix.env() + release_dir = "_build/#{env}/rel/#{app}" - cmd = "cd #{path} && zip -r lambda.zip * && cp lambda.zip #{System.cwd()}" + cmd = "cd #{release_dir} && \ + chmod +x bin/#{app} && \ + chmod +x releases/#{version}/elixir && \ + chmod +x releases/#{version}/*.sh && \ + chmod +x erts-*/bin/* && \ + zip -r #{app}_lambda.zip * && \ + mv #{app}_lambda.zip ../" System.cmd("sh", ["-c", cmd]) end @@ -19,7 +28,9 @@ defmodule Mix.Tasks.Zip do |> to_string end - defp release_path(app) do - "_build/#{Mix.env()}/rel/#{app}/" + defp app_version() do + Mix.Project.config() + |> Keyword.fetch!(:version) + |> to_string end end diff --git a/elixir_runtime/mix.exs b/elixir_runtime/mix.exs index 36ca8ef..ffefdd2 100644 --- a/elixir_runtime/mix.exs +++ b/elixir_runtime/mix.exs @@ -8,7 +8,7 @@ defmodule Lambda.MixProject do [ app: :aws_lambda_elixir_runtime, version: "0.1.0", - elixir: "~> 1.7", + elixir: "~> 1.15", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, deps: deps(), @@ -17,7 +17,8 @@ defmodule Lambda.MixProject do # Docs name: "AWS Lambda Elixir Runtime", source_url: "https://github.com/aws-samples/aws-lambda-elixir-runtime", - homepage_url: "https://github.com/aws-samples/aws-lambda-elixir-runtime/tree/master/elixir_runtime", + homepage_url: + "https://github.com/aws-samples/aws-lambda-elixir-runtime/tree/master/elixir_runtime", docs: [ source_url_pattern: "https://github.com/aws-samples/aws-lambda-elixir-runtime/blob/master/elixir_runtime/%{path}#L%{line}", @@ -34,16 +35,17 @@ defmodule Lambda.MixProject do def application do [ mod: {ElixirRuntime.Application, []}, - extra_applications: [:logger, :inets] + extra_applications: [:logger, :inets, :ssl] ] end # Run "mix help deps" to learn about dependencies. defp deps do [ - {:poison, "~> 3.1"}, - {:mox, "~> 0.4", only: :test}, - {:ex_doc, "~> 0.19", only: :dev, runtime: false} + {:poison, "~> 5.0"}, + {:mox, "~> 1.0", only: :test}, + {:ex_doc, "~> 0.27", only: :dev, runtime: false}, + {:castore, "~> 1.0", only: [:dev, :test]} ] end diff --git a/elixir_runtime/priv/.DS_Store b/elixir_runtime/priv/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7162d389af648fd68f532edd0fd3acf612cd786f GIT binary patch literal 6148 zcmeHK!AiqG5Z!HSn^J@x6g@6@E!a{ih?fxS4;aydN==%ep)p&M)E-J9SN$RX#P4xt zcO!)A#e+zhftfd*o!N9>%1(zd#+^klV64j+vp^ARZ7|;muA^>9%|z;eTry~n%FT$ubveX^$+Ha>8g)72X87Rd$=pmRTso!SYX#^7C<^8k8ox@wQLPwq eu@xVJDuK8_2hcWHXoLs|{Si0fyY&L`kU9u9_v`MCW>Dz^OQu zeyu*ApSC&;**=gK!OU z%M36B%M27vw?_5veHSwzjS;j%uw$eLy9lxXj>J3L3f; gV=R^8I;s}*OEM5$iH1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 1.7", + elixir: "~> 1.15", start_permanent: Mix.env() == :prod, - deps: deps() + deps: deps(), + releases: [ + hello_world: [ + version: "0.1.0", + applications: [hello_world: :permanent, aws_lambda_elixir_runtime: :permanent], + include_erts: true, + include_executables_for: [:unix], + + ] + ] ] end @@ -24,8 +33,7 @@ defmodule HelloWorld.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:aws_lambda_elixir_runtime, path: "../../elixir_runtime"}, - {:distillery, "~> 2.0"} + {:aws_lambda_elixir_runtime, path: "../../elixir_runtime"} ] end end diff --git a/examples/hello_world/rel/config.exs b/examples/hello_world/rel/config.exs deleted file mode 100644 index 42274c5..0000000 --- a/examples/hello_world/rel/config.exs +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: MIT-0 - -~w(rel plugins *.exs) -|> Path.join() -|> Path.wildcard() -|> Enum.map(&Code.eval_file(&1)) - -use Mix.Releases.Config, - default_release: :hello_world, - default_environment: :lambda - -environment :lambda do - set include_erts: true - set include_src: false - set cookie: :test - set include_system_libs: true - - # Distillery forces the ERTS into 'distributed' mode which will - # attempt to connect to EPMD. This is not supported behavior in the - # AWS Lambda runtime because our process isn't allowed to connect to - # other ports on this host. - # - # So '-start_epmd false' is set so the ERTS doesn't try to start EPMD. - # And '-epmd_module' is set to use a no-op implementation of EPMD - set erl_opts: "-start_epmd false -epmd_module Elixir.EPMD.StubClient" -end - -release :hello_world do - set version: current_version(:hello_world) - set applications: [ - :runtime_tools, :aws_lambda_elixir_runtime - ] -end diff --git a/examples/hello_world/rel/env.bat.eex b/examples/hello_world/rel/env.bat.eex new file mode 100644 index 0000000..0d82afd --- /dev/null +++ b/examples/hello_world/rel/env.bat.eex @@ -0,0 +1,8 @@ +@echo off +rem Set the release to load code on demand (interactive) instead of preloading (embedded). +rem set RELEASE_MODE=interactive + +rem Set the release to work across nodes. +rem RELEASE_DISTRIBUTION must be "sname" (local), "name" (distributed) or "none". +rem set RELEASE_DISTRIBUTION=name +rem set RELEASE_NODE=<%= @release.name %> diff --git a/examples/hello_world/rel/env.sh.eex b/examples/hello_world/rel/env.sh.eex new file mode 100644 index 0000000..ab7b76a --- /dev/null +++ b/examples/hello_world/rel/env.sh.eex @@ -0,0 +1,20 @@ +#!/bin/sh + +# # Sets and enables heart (recommended only in daemon mode) +# case $RELEASE_COMMAND in +# daemon*) +# HEART_COMMAND="$RELEASE_ROOT/bin/$RELEASE_NAME $RELEASE_COMMAND" +# export HEART_COMMAND +# export ELIXIR_ERL_OPTIONS="-heart" +# ;; +# *) +# ;; +# esac + +# # Set the release to load code on demand (interactive) instead of preloading (embedded). +# export RELEASE_MODE=interactive + +# # Set the release to work across nodes. +# # RELEASE_DISTRIBUTION must be "sname" (local), "name" (distributed) or "none". +# export RELEASE_DISTRIBUTION=name +# export RELEASE_NODE=<%= @release.name %> diff --git a/examples/hello_world/rel/remote.vm.args.eex b/examples/hello_world/rel/remote.vm.args.eex new file mode 100644 index 0000000..983397a --- /dev/null +++ b/examples/hello_world/rel/remote.vm.args.eex @@ -0,0 +1,8 @@ +## Customize flags given to the VM: https://www.erlang.org/doc/man/erl.html +## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here + +## Increase number of concurrent ports/sockets +##+Q 65536 + +## Tweak GC to run more often +##-env ERL_FULLSWEEP_AFTER 10 diff --git a/examples/hello_world/rel/vm.args.eex b/examples/hello_world/rel/vm.args.eex new file mode 100644 index 0000000..d6553e2 --- /dev/null +++ b/examples/hello_world/rel/vm.args.eex @@ -0,0 +1,16 @@ +## Customize flags given to the VM: https://www.erlang.org/doc/man/erl.html +## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here + +## Increase number of concurrent ports/sockets +##+Q 65536 + +## Tweak GC to run more often +##-env ERL_FULLSWEEP_AFTER 10 + +# Running ERTS in distributed mode will attempt to connect to EPMD. +# This is not supported behavior in the AWS Lambda runtime because our +# process isn't allowed to connect to other ports on this host. +# +# So '-start_epmd false' is set so the ERTS doesn't try to start EPMD. +# And '-epmd_module' is set to use a no-op implementation of EPMD +-start_epmd false -epmd_module Elixir.EPMD.StubClient diff --git a/examples/hello_world/response.json b/examples/hello_world/response.json new file mode 100644 index 0000000..c0b80db --- /dev/null +++ b/examples/hello_world/response.json @@ -0,0 +1 @@ +{"errorType":"Runtime.ExitError","errorMessage":"RequestId: 639ebc1a-a9fd-40bf-906e-97a213864511 Error: Runtime exited with error: exit status 126"} \ No newline at end of file From 48a45eec09a288a7391b9b661347f1023d496360 Mon Sep 17 00:00:00 2001 From: Carsten Piepel Date: Wed, 2 Aug 2023 15:23:26 -0700 Subject: [PATCH 02/11] Fixed LD_LIBRARY_PATH. --- elixir_runtime/lib/mix/tasks/bootstrap.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elixir_runtime/lib/mix/tasks/bootstrap.ex b/elixir_runtime/lib/mix/tasks/bootstrap.ex index a9a3a4b..1e942fb 100644 --- a/elixir_runtime/lib/mix/tasks/bootstrap.ex +++ b/elixir_runtime/lib/mix/tasks/bootstrap.ex @@ -9,7 +9,7 @@ defmodule Mix.Tasks.Bootstrap do use Mix.Task - @runtime_libs "elixir_runtime-0.1.0/priv" + @runtime_libs "aws_lambda_elixir_runtime-0.1.0/priv" @shortdoc "Generate a bootstrap script for the project" def run(_) do From 86e4f78e9f5631e2f227d5d685fed81413ae4333 Mon Sep 17 00:00:00 2001 From: carstenpiepel Date: Wed, 2 Aug 2023 22:26:15 +0000 Subject: [PATCH 03/11] Resolves aws-samples/aws-lambda-elixir-runtime#15 by updating shared objects --- elixir_runtime/priv/libcrypto.so.1.0.0 | Bin 2361856 -> 0 bytes elixir_runtime/priv/libcrypto.so.1.1 | Bin 0 -> 3005016 bytes elixir_runtime/priv/libssl.so | Bin 428384 -> 585136 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 elixir_runtime/priv/libcrypto.so.1.0.0 create mode 100755 elixir_runtime/priv/libcrypto.so.1.1 diff --git a/elixir_runtime/priv/libcrypto.so.1.0.0 b/elixir_runtime/priv/libcrypto.so.1.0.0 deleted file mode 100644 index 0f177da59afe4664686e3a58dc1da7afc617b989..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2361856 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

GfRP5Sh< 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