Current section

Files

Jump to
erlang_python examples shared_state_example.erl
Raw

examples/shared_state_example.erl

#!/usr/bin/env escript
%%% @doc Shared state example - demonstrates sharing data between Python workers.
%%%
%%% Since each Python worker has its own namespace, functions and variables
%%% defined in one call aren't visible in another. The shared state API
%%% provides ETS-backed storage accessible from both Python and Erlang.
%%%
%%% Prerequisites: rebar3 compile
%%% Run from project root: escript examples/shared_state_example.erl
-mode(compile).
main(_) ->
%% Add the compiled beam files to the code path
ScriptDir = filename:dirname(escript:script_name()),
ProjectRoot = filename:dirname(ScriptDir),
EbinDir = filename:join([ProjectRoot, "_build", "default", "lib", "erlang_python", "ebin"]),
true = code:add_pathz(EbinDir),
{ok, _} = application:ensure_all_started(erlang_python),
io:format("~n=== Shared State Example ===~n~n"),
%% Clear any existing state
py:state_clear(),
%% Example 1: Set from Erlang, read from Python
io:format("1. Erlang -> Python:~n"),
py:state_store(<<"config">>, #{
api_key => <<"secret123">>,
max_retries => 3,
timeout => 5000
}),
%% Python reads using idiomatic import syntax
ok = py:exec(<<"
from erlang import state_get
config = state_get('config')
assert config['api_key'] == 'secret123'
assert config['max_retries'] == 3
">>),
io:format(" Python read config successfully~n"),
%% Example 2: Set from Python, read from Erlang
io:format("~n2. Python -> Erlang:~n"),
ok = py:exec(<<"
from erlang import state_set
state_set('computation_result', {
'status': 'complete',
'values': [1, 2, 3, 4, 5],
'metadata': {'source': 'python', 'timestamp': 1234567890}
})
">>),
{ok, Result} = py:state_fetch(<<"computation_result">>),
io:format(" Result in Erlang: ~p~n", [Result]),
%% Example 3: Atomic counters - thread-safe increment/decrement
io:format("~n3. Atomic counters (thread-safe):~n"),
%% From Erlang
Val1 = py:state_incr(<<"hits">>),
io:format(" Erlang incr: ~p~n", [Val1]),
Val2 = py:state_incr(<<"hits">>, 10),
io:format(" Erlang incr by 10: ~p~n", [Val2]),
%% From Python
ok = py:exec(<<"
from erlang import state_incr, state_decr
val = state_incr('hits', 5)
print(f' Python incr by 5: {val}')
val = state_decr('hits', 3)
print(f' Python decr by 3: {val}')
">>),
{ok, FinalCount} = py:state_fetch(<<"hits">>),
io:format(" Final counter value: ~p~n", [FinalCount]),
%% Example 4: List all keys from Python
io:format("~n4. List keys from Python:~n"),
ok = py:exec(<<"
from erlang import state_keys
keys = state_keys()
assert 'hits' in keys
assert 'config' in keys
">>),
Keys = py:state_keys(),
io:format(" Keys: ~p~n", [Keys]),
%% Example 5: Delete from Python
io:format("~n5. Delete from Python:~n"),
ok = py:exec(<<"
from erlang import state_delete
state_delete('computation_result')
">>),
case py:state_fetch(<<"computation_result">>) of
{error, not_found} -> io:format(" Key deleted successfully~n");
{ok, _} -> io:format(" ERROR: Key still exists~n")
end,
%% Cleanup
py:state_clear(),
io:format("~n=== Done ===~n~n"),
ok = application:stop(erlang_python).