ZastrixArundell
So I have this erlport connection module:
defmodule PheedThePi.PythonConnection do
@moduledoc """
Module responsible for the Python connection and IO.
"""
def start() do
path = [
:code.priv_dir(:pheed_the_pi), "python"
] |> Path.join() |> IO.inspect(label: "Python priv path")
{:ok, pid} = :python.start([{:python_path, to_charlist(path)}])
pid
end
def call(pid, module, function, arguments \\ []), do:
:python.call(pid, module, function, arguments)
def cast(pid, message), do:
:python.cast(pid, message)
def stop(pid), do:
:python.stop(pid)
end
And my GenServer for the connection:
defmodule PheedThePi.PythonServer do
@moduledoc """
GenServer which manages the Python erlang port.
"""
use GenServer
alias PheedThePi.PythonConnection, as: Python
def start_link(_), do:
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
def init(_) do
# Get the pid of the python session.
python_session = Python.start()
# Start the connection to the python session.
Python.call(python_session, :api, :register_handler, [self()])
{:ok, python_session}
end
# Call a specific function given an atom as the function name
@spec cast_function(atom(), list(any())) :: :ok
def cast_function(function, arguments), do:
GenServer.cast(__MODULE__, {function, arguments})
# Send a general message to Python
@spec send_message(any) :: :ok
def send_message(message), do:
GenServer.cast(__MODULE__, {:python_message, message})
def handle_cast({:python_message, message}, python_session) do
Python.cast(python_session, message)
{:noreply, python_session}
end
def handle_cast({function, arguments}, python_session) do
Python.call(python_session, :api, function, arguments)
{:noreply, python_session}
end
def handle_info({:python, message}, python_session) do
IO.write "Got message from Python: #{message}\n"
{:noreply, python_session}
end
def terminate(_reason, python_session) do
Python.stop(python_session)
end
end
And my Python code:
from erlport.erlang import set_message_handler, cast
from erlport.erlterms import Atom
message_handler = None #reference to the elixir process to send result to
def message(message):
message = message.decode("utf-8")
print('Hey, python has gotten the message: ' + message)
return 'test'
def cast_message(pid, message):
cast(pid, (Atom(b'python'), message))
def register_handler(pid):
#save message handler pid
global message_handler
message_handler = pid
def handle_message(message):
message = message.decode("utf-8")
print("Received message from Elixir: " + message)
cast_message(message_handler, 'Here you go: ' + message)
set_message_handler(handle_message)
Now this works when you run expected code:
PheedThePi.PythonServer.send_message "this is a message"
:ok
iex(12)> Received message from Elixir: this is a message
Got message from Python: Here you go: this is a message
But if I were to do something stupid like:
iex(12)> PheedThePi.PythonServer.send_message 1+1
:ok
iex(13)> [error] GenServer #PID<0.420.0> terminating
** (stop) {:message_handler_error, {:python, :"builtins.AttributeError", '\'int\' object has no attribute \'decode\'', [' File "/home/zastrix/Documents/Personal/Phoenix/pheed_the_pi/_build/dev/lib/pheed_the_pi/priv/python/api.py", line 20, in handle_message\n message = message.decode("utf-8")\n', ' File "/home/zastrix/Documents/Personal/Phoenix/pheed_the_pi/_build/dev/lib/erlport/priv/python3/erlport/erlang.py", line 233, in _call_with_error_handler\n function(*args)\n']}}
Last message: {#Port<0.10>, {:data, <<131, 104, 2, 100, 0, 1, 101, 104, 4, 100, 0, 6, 112, 121, 116, 104, 111, 110, 100, 0, 23, 98, 117, 105, 108, 116, 105, 110, 115, 46, 65, 116, 116, 114, 105, 98, 117, 116, 101, 69, 114, 114, 111, 114, 107, 0, ...>>}}
State: {:state, :infinity, 0, #Port<0.10>, [], []}
I get an error message, and my erlport process dies, not my GenServer so it doesn’t restart. I couldn’t find a way but is it possible to perhaps add a Supervisor to my GenServer which supercises the erlport process?
Trending in Questions
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
Hello,
I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security











Showing Posts 1 to 6- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
kokolegorille
Why don’t You check here for valid input? If You expect binaries, but not 1 + 1, You could use a guard…
…using any here, means anything would be ok, even 1 + 1
ZastrixArundell
That was just an example of how to generate an error. In this case it was 1+1 but it will kill the Erlport GenServer if there is an exception on the Python side of code as well. It would crash it if I didn’t utf-8 decode the message argument. (Again, the code would crash if any random exception happened within Python)
I just want to know that if it is possible to supervise an Erlport, how do I do that. I’d like to supervise it from my GenServer.
kokolegorille
As it is just a process, You could monitor it, catch DOWN message… then take appropriate mesure.
BTW there is also a :python.start_link() so it is easy to link it to another process.
ZastrixArundell
Thanks but I found an relatively easy solution. I just linked my GenServer to the erlport pid and now when it crashes, it crashes my supervised genserver. Here is the new code:
kokolegorille
Nice You find a solution.
I would trap exit from this GenServer, and restart the python session upon receiving a DOWN message… avoiding the GenSever restart, but it’s just cosmetic.
BTW You could use the following line, as it is atomic.
instead of…
ZastrixArundell
Thanks. I didn’t know that the difference between
startandstart_linkis thatstart_linkbasically links the process to the caller (I mean, now it makes sense when I wrote it). I’ll give you a solution as it’s basically what I’ve done but better ahahah!