I have a phoenix app, where I’m using liveview to get user inputs through a UI. These inputs get packaged into JSON and sent to a python business process (script), which in turn returns the results in JSON to the liveview, where they get displayed.
I am sending my JSON successfully to the python, running it and getting the results, however I don’t get the result when running it from liveview (when I run my python mynaully in the terminal, the results json is returned fine). It should be a straightforward thing, im sure im missing a really easy point. Can anyone help? FYI, my python business process takes 0.03 seconds tu run when running manually from start to finish
Python I'm calling:
def main():
try:
raw_input = sys.stdin.read().strip()
input_data = json.loads(raw_input)
results = optimizer_function(input_data) # optimizer_function is my business process
output = json.dumps(results)
sys.stdout.write(output + "\n")
sys.stdout.flush()
except Exception as e:
sys.stdout.write(json.dumps({"error": str(e)}) + "\n")
sys.stdout.flush()
if __name__ == "__main__":
main()
My Phoenix Optimizer business process code snippets:
defmodule Commrefiner.Optimizer do
def run_optimizer(params) do
json_input = Jason.encode!(params)
script_path = Application.fetch_env!(:commrefiner, :optimizer_script_path)
port = Port.open({:spawn_executable, "path/to/virtual/environment/python3"}, [
{:args, [script_path]},
:binary,
:exit_status,
:use_stdio,
:stderr_to_stdout
])
Portmand(port, json_input <> "\n")
response = collect_output(port, "")
Port.close(port)
case Jason.decode(response) do
{:ok, result} -> result
{:error, _} -> %{"error" => "Invalid JSON response from optimizer"}
end
end
defp collect_output(port, acc) do
case Port.info(port, :os_pid) do
{:os_pid, _pid} ->
receive do
{^port, {:data, output}} -> collect_output(port, acc <> output)
{^port, {:exit_status, status}} -> acc
after
15_000 -> # ✅ Allow enough time for Python output
acc
end
nil ->
acc
end
end
end
My Phoenix Live_view code snippets:
def handle_event("run_optimizer", _params, socket) do
params = %{params: socket.assigns.user_inputs}
headers = [{"Content-Type", "application/json"}] # Define and ensure correct headers
# encode JSON before sending
response = HTTPoison.post("http://localhost:4000/api/optimizer", Jason.encode!(params), headers)
case response do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
case Jason.decode(body) do
{:ok, results} -> {:noreply, assign(socket, results: results)}
{:error, _} -> {:noreply, assign(socket, results: %{"error" => "Invalid JSON response"})}
end
{:ok, %HTTPoison.Response{status_code: code, body: body}} -> # ✅ Handle non-200 responses
IO.puts("❌ API returned status #{code}")
IO.inspect(body, label: "Non-200 Response")
{:noreply, assign(socket, results: %{"error" => "API error: #{code}"})}
{:error, %HTTPoison.Error{reason: reason}} -> # ✅ Handle request errors
IO.puts("❌ Optimizer API request failed")
IO.inspect(reason, label: "Optimizer API Error")
{:noreply, assign(socket, results: %{"error" => "Failed to call optimizer"})}
end
end
My logs indicate:
Timeout in the Phoenix API request:
- Optimizer API Error: :timeout
- Python process timed out. Partial Data: "" Python script does not send any output before the timeout:
- Full Raw Response from Python: ""
- Raw Python Output: "" What’s Happening?
- Phoenix opens the port to run the Python script.
- It sends the JSON input.
- Python does not send output before the timeout.
- The API request times out before Python can return data.
- Phoenix closes the connection, causing Python to fail with BrokenPipeError.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745196780a4616133.html
评论列表(0条)