@@ -60,7 +60,7 @@ defmodule NodeJS.Worker do
6060 ]
6161 )
6262
63- { :ok , [ node_service_path ( ) , port ] }
63+ { :ok , % { service_path: node_service_path ( ) , port: port , uid_counter: 0 } }
6464 end
6565
6666 defp get_env_vars ( module_path ) do
@@ -70,29 +70,48 @@ defmodule NodeJS.Worker do
7070 ]
7171 end
7272
73- defp get_response ( data , timeout ) do
73+ defp get_response ( data , timeout , port , expected_uid ) do
7474 receive do
75- { _port , { :data , { flag , chunk } } } ->
75+ { ^ port , { :data , { flag , chunk } } } ->
7676 data = data ++ chunk
7777
7878 case flag do
7979 :noeol ->
80- get_response ( data , timeout )
80+ get_response ( data , timeout , port , expected_uid )
8181
8282 :eol ->
8383 case data do
84- @ prefix ++ protocol_data -> { :ok , protocol_data }
85- _ -> get_response ( ~c" " , timeout )
84+ @ prefix ++ protocol_data ->
85+ case extract_uid ( protocol_data ) do
86+ { ^ expected_uid , response_data } ->
87+ { :ok , response_data }
88+
89+ { _stale_uid , _response_data } ->
90+ # Response from a different (likely timed-out) request — discard it
91+ get_response ( ~c" " , timeout , port , expected_uid )
92+ end
93+
94+ _ ->
95+ get_response ( ~c" " , timeout , port , expected_uid )
8696 end
8797 end
8898
89- { _port , { :exit_status , status } } when status != 0 ->
99+ { ^ port , { :exit_status , status } } when status != 0 ->
90100 { :error , { :exit , status } }
91101 after
92102 timeout -> { :error , :timeout }
93103 end
94104 end
95105
106+ # Extracts the UID and response data from protocol data.
107+ # Protocol format: "uid:json_response"
108+ defp extract_uid ( data ) do
109+ case Enum . split_while ( data , & ( & 1 != ?: ) ) do
110+ { uid_chars , [ ?: | rest ] } -> { List . to_string ( uid_chars ) , rest }
111+ _ -> { "" , data }
112+ end
113+ end
114+
96115 defp decode_binary ( data , binary ) do
97116 if binary === true do
98117 :binary . list_to_bin ( data )
@@ -102,15 +121,18 @@ defmodule NodeJS.Worker do
102121 end
103122
104123 @ doc false
105- def handle_call ( { module , args , opts } , _from , [ _ , port ] = state )
124+ def handle_call ( { module , args , opts } , _from , % { port: port , uid_counter: uid_counter } = state )
106125 when is_tuple ( module ) do
107126 timeout = Keyword . get ( opts , :timeout )
108127 binary = Keyword . get ( opts , :binary )
109128 esm = Keyword . get ( opts , :esm , false )
110- body = Jason . encode! ( [ Tuple . to_list ( module ) , args , esm ] )
129+ uid = Integer . to_string ( uid_counter )
130+ body = Jason . encode! ( [ uid , Tuple . to_list ( module ) , args , esm ] )
111131 Port . command ( port , "#{ body } \n " )
112132
113- case get_response ( ~c" " , timeout ) do
133+ state = % { state | uid_counter: uid_counter + 1 }
134+
135+ case get_response ( ~c" " , timeout , port , uid ) do
114136 { :ok , response } ->
115137 decoded_response =
116138 response
@@ -169,7 +191,7 @@ defmodule NodeJS.Worker do
169191 end
170192
171193 @ doc false
172- def terminate ( _reason , [ _ , port ] ) do
194+ def terminate ( _reason , % { port: port } ) do
173195 reset_terminal ( port )
174196 send ( port , { self ( ) , :close } )
175197 end
0 commit comments