From b40953a298671c449749b50c21277b1498636755 Mon Sep 17 00:00:00 2001 From: Benoit Chesneau Date: Thu, 12 Mar 2026 12:38:00 +0100 Subject: [PATCH 1/4] Update erlang_python to latest main branch --- rebar.config | 2 +- rebar.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rebar.config b/rebar.config index 0043d41..88a2b0b 100644 --- a/rebar.config +++ b/rebar.config @@ -20,7 +20,7 @@ {deps, [ {cowboy, "2.12.0"}, - {erlang_python, "1.8.1"} + {erlang_python, {git, "https://github.com/benoitc/erlang_python.git", {branch, "main"}}} ]}. {shell, [ diff --git a/rebar.lock b/rebar.lock index ecd87bb..d0509f1 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,17 +1,18 @@ {"1.2.0", [{<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.12.0">>},0}, {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.13.0">>},1}, - {<<"erlang_python">>,{pkg,<<"erlang_python">>,<<"1.8.1">>},0}, + {<<"erlang_python">>, + {git,"https://github.com/benoitc/erlang_python.git", + {ref,"f37dfbe894b6d1c74e44b9cbe1720bb949467caa"}}, + 0}, {<<"ranch">>,{pkg,<<"ranch">>,<<"1.8.0">>},1}]}. [ {pkg_hash,[ {<<"cowboy">>, <<"F276D521A1FF88B2B9B4C54D0E753DA6C66DD7BE6C9FCA3D9418B561828A3731">>}, {<<"cowlib">>, <<"DB8F7505D8332D98EF50A3EF34B34C1AFDDEC7506E4EE4DD4A3A266285D282CA">>}, - {<<"erlang_python">>, <<"4DAFC7AFD315F0D5D45792F722364D8721CED438E396B7D14F19518DC78D198B">>}, {<<"ranch">>, <<"8C7A100A139FD57F17327B6413E4167AC559FBC04CA7448E9BE9057311597A1D">>}]}, {pkg_hash_ext,[ {<<"cowboy">>, <<"8A7ABE6D183372CEB21CAA2709BEC928AB2B72E18A3911AA1771639BEF82651E">>}, {<<"cowlib">>, <<"E1E1284DC3FC030A64B1AD0D8382AE7E99DA46C3246B815318A4B848873800A4">>}, - {<<"erlang_python">>, <<"0F5893100A92285096519F8111D3A6D3F5DCD18668545ADF9F4144899D5997C2">>}, {<<"ranch">>, <<"49FBCFD3682FAB1F5D109351B61257676DA1A2FDBE295904176D5E521A2DDFE5">>}]} ]. From d56b266a2e5c4ec5cb7e23467c943af0d7da570f Mon Sep 17 00:00:00 2001 From: Benoit Chesneau Date: Thu, 12 Mar 2026 12:41:39 +0100 Subject: [PATCH 2/4] Update hackney to 3.2.1 --- rebar.config | 2 +- rebar.lock | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 rebar.lock diff --git a/rebar.config b/rebar.config index 88a2b0b..3d6fdba 100644 --- a/rebar.config +++ b/rebar.config @@ -39,7 +39,7 @@ {profiles, [ {test, [ {deps, [ - {hackney, "3.0.2"}, + {hackney, "3.2.1"}, {jsx, "3.1.0"} ]} ]} diff --git a/rebar.lock b/rebar.lock deleted file mode 100644 index d0509f1..0000000 --- a/rebar.lock +++ /dev/null @@ -1,18 +0,0 @@ -{"1.2.0", -[{<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.12.0">>},0}, - {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.13.0">>},1}, - {<<"erlang_python">>, - {git,"https://github.com/benoitc/erlang_python.git", - {ref,"f37dfbe894b6d1c74e44b9cbe1720bb949467caa"}}, - 0}, - {<<"ranch">>,{pkg,<<"ranch">>,<<"1.8.0">>},1}]}. -[ -{pkg_hash,[ - {<<"cowboy">>, <<"F276D521A1FF88B2B9B4C54D0E753DA6C66DD7BE6C9FCA3D9418B561828A3731">>}, - {<<"cowlib">>, <<"DB8F7505D8332D98EF50A3EF34B34C1AFDDEC7506E4EE4DD4A3A266285D282CA">>}, - {<<"ranch">>, <<"8C7A100A139FD57F17327B6413E4167AC559FBC04CA7448E9BE9057311597A1D">>}]}, -{pkg_hash_ext,[ - {<<"cowboy">>, <<"8A7ABE6D183372CEB21CAA2709BEC928AB2B72E18A3911AA1771639BEF82651E">>}, - {<<"cowlib">>, <<"E1E1284DC3FC030A64B1AD0D8382AE7E99DA46C3246B815318A4B848873800A4">>}, - {<<"ranch">>, <<"49FBCFD3682FAB1F5D109351B61257676DA1A2FDBE295904176D5E521A2DDFE5">>}]} -]. From 83460311d3e7d91daf642368fcfa79da1d4cb365 Mon Sep 17 00:00:00 2001 From: Benoit Chesneau Date: Thu, 12 Mar 2026 14:44:21 +0100 Subject: [PATCH 3/4] Update to erlang_python new API - Fix erlang_python git repo URL (erlang-python not erlang_python) - Replace py:bind/py:unbind with py:context/py:contexts_started - Replace py:ctx_call with py:call - Replace py:with_context with direct py:call - Update py:call signatures to use options map for timeout --- rebar.config | 2 +- src/hornbeam_handler.erl | 20 +++++++++----------- src/hornbeam_lifespan.erl | 26 +++++++++++--------------- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/rebar.config b/rebar.config index 3d6fdba..f840efa 100644 --- a/rebar.config +++ b/rebar.config @@ -20,7 +20,7 @@ {deps, [ {cowboy, "2.12.0"}, - {erlang_python, {git, "https://github.com/benoitc/erlang_python.git", {branch, "main"}}} + {erlang_python, {git, "https://github.com/benoitc/erlang-python.git", {branch, "main"}}} ]}. {shell, [ diff --git a/src/hornbeam_handler.erl b/src/hornbeam_handler.erl index 8621741..a5526ee 100644 --- a/src/hornbeam_handler.erl +++ b/src/hornbeam_handler.erl @@ -146,7 +146,7 @@ run_wsgi_optimized(Req, AppModule, AppCallable, State) -> end. %% @private -%% Context-aware fallback path using py:ctx_call +%% Context-aware fallback path using py:call run_wsgi_with_context(Req, AppModule, AppCallable, PyContext, TimeoutMs, State) -> %% Build environ options from state (for multi-app mode) EnvOpts = case maps:get(script_name, State, undefined) of @@ -159,8 +159,8 @@ run_wsgi_with_context(Req, AppModule, AppCallable, PyContext, TimeoutMs, State) undefined -> Environ; PathInfo -> Environ#{<<"PATH_INFO">> => PathInfo} end, - py:ctx_call(PyContext, hornbeam_wsgi_runner, run_wsgi, - [AppModule, AppCallable, Environ1], #{}, TimeoutMs). + py:call(PyContext, hornbeam_wsgi_runner, run_wsgi, + [AppModule, AppCallable, Environ1], #{timeout => TimeoutMs}). %% @private %% Build environ dict for NIF optimization. @@ -356,7 +356,7 @@ run_asgi_optimized(Req, AppModule, AppCallable, ReqBody, State) -> end. %% @private -%% Context-aware fallback path using py:ctx_call +%% Context-aware fallback path using py:call run_asgi_with_context(Req, AppModule, AppCallable, ReqBody, PyContext, TimeoutMs, State) -> %% Build scope options from state (for multi-app mode) ScopeOpts = case maps:get(script_name, State, undefined) of @@ -369,8 +369,8 @@ run_asgi_with_context(Req, AppModule, AppCallable, ReqBody, PyContext, TimeoutMs undefined -> Scope; PathInfo -> Scope#{<<"path">> => PathInfo, <<"raw_path">> => PathInfo} end, - py:ctx_call(PyContext, hornbeam_asgi_runner, run_asgi, - [AppModule, AppCallable, Scope1, ReqBody], #{}, TimeoutMs). + py:call(PyContext, hornbeam_asgi_runner, run_asgi, + [AppModule, AppCallable, Scope1, ReqBody], #{timeout => TimeoutMs}). %% @private %% Bound context path - binds a worker for the request duration. @@ -388,11 +388,9 @@ run_asgi_bound(Req, AppModule, AppCallable, ReqBody, TimeoutMs, State) -> undefined -> Scope; PathInfo -> Scope#{<<"path">> => PathInfo, <<"raw_path">> => PathInfo} end, - %% Use with_context to bind a worker for the request duration - py:with_context(fun() -> - py:call(hornbeam_asgi_runner, run_asgi, - [AppModule, AppCallable, Scope1, ReqBody], #{}, TimeoutMs) - end). + %% Call ASGI runner - context routing handled automatically by py:call + py:call(hornbeam_asgi_runner, run_asgi, + [AppModule, AppCallable, Scope1, ReqBody], #{}, TimeoutMs). %% @private %% Build scope with atom keys for NIF optimization. diff --git a/src/hornbeam_lifespan.erl b/src/hornbeam_lifespan.erl index c6ba3e7..b735d2b 100644 --- a/src/hornbeam_lifespan.erl +++ b/src/hornbeam_lifespan.erl @@ -155,11 +155,11 @@ init(Opts) -> {read_concurrency, true} ]), - %% Create a dedicated Python context for ASGI affinity + %% Get a Python context for ASGI affinity %% This ensures module-level state persists across requests - PyContext = case py:bind(new) of - {ok, Ctx} -> Ctx; - _ -> undefined + PyContext = case py:contexts_started() of + true -> py:context(); + false -> undefined end, %% Cache initial values @@ -261,12 +261,8 @@ terminate(_Reason, #state{started = true, supported = true, py_context = PyContext}) -> %% Run shutdown on terminate _ = run_shutdown(AppModule, AppCallable, PyContext), - %% Unbind the context - catch py:unbind(PyContext), ok; -terminate(_Reason, #state{py_context = PyContext}) -> - %% Just unbind context if lifespan not started - catch py:unbind(PyContext), +terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> @@ -293,10 +289,10 @@ run_startup(AppModule, AppCallable, PyContext) -> Result = case PyContext of undefined -> py:call(hornbeam_lifespan_runner, startup, - [AppModule, AppCallable, TimeoutMs], #{}, TimeoutMs + 5000); + [AppModule, AppCallable, TimeoutMs], #{timeout => TimeoutMs + 5000}); Ctx -> - py:ctx_call(Ctx, hornbeam_lifespan_runner, startup, - [AppModule, AppCallable, TimeoutMs], #{}, TimeoutMs + 5000) + py:call(Ctx, hornbeam_lifespan_runner, startup, + [AppModule, AppCallable, TimeoutMs], #{timeout => TimeoutMs + 5000}) end, case Result of {ok, Response} -> @@ -337,10 +333,10 @@ run_shutdown(AppModule, AppCallable, PyContext) -> Result = case PyContext of undefined -> py:call(hornbeam_lifespan_runner, shutdown, - [AppModule, AppCallable], #{}, TimeoutMs); + [AppModule, AppCallable], #{timeout => TimeoutMs}); Ctx -> - py:ctx_call(Ctx, hornbeam_lifespan_runner, shutdown, - [AppModule, AppCallable], #{}, TimeoutMs) + py:call(Ctx, hornbeam_lifespan_runner, shutdown, + [AppModule, AppCallable], #{timeout => TimeoutMs}) end, case Result of {ok, Response} -> From e83367e302166f7e762159438fb6e1d54879374b Mon Sep 17 00:00:00 2001 From: Benoit Chesneau Date: Thu, 12 Mar 2026 14:48:04 +0100 Subject: [PATCH 4/4] Update erlang_python to hex 2.1.0 --- rebar.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index f840efa..1899428 100644 --- a/rebar.config +++ b/rebar.config @@ -20,7 +20,7 @@ {deps, [ {cowboy, "2.12.0"}, - {erlang_python, {git, "https://github.com/benoitc/erlang-python.git", {branch, "main"}}} + {erlang_python, "2.1.0"} ]}. {shell, [