@@ -674,7 +674,7 @@ checkin_info(Pid) ->
674674 checkin_info (Pid , 5000 ).
675675
676676% % @doc Checkin flags, waiting at most `Timeout'. @see get_state/2
677- -spec checkin_info (pid (), timeout ()) -> map ().
677+ -spec checkin_info (pid (), timeout ()) -> map () | { error , term ()} .
678678checkin_info (Pid , Timeout ) ->
679679 gen_statem :call (Pid , checkin_info , Timeout ).
680680
@@ -1824,8 +1824,8 @@ closed(enter, _OldState, #conn_data{socket = Socket, transport = Transport, pool
18241824 % % late-arriving {call, From, {request, _}} messages from workers that
18251825 % % raced the pool checkout race a terminating gen_statem — which
18261826 % % surfaces as `exit:{normal, _}` in the caller (issue #836). Stay
1827- % % alive briefly so those late calls get a proper `{error, { closed, _} }`
1828- % % reply via handle_common's invalid_state fallback , then stop.
1827+ % % alive briefly so those late calls get a proper `{error, closed}`
1828+ % % reply via the dedicated closed/3 catch-all clause below , then stop.
18291829 case PoolPid of
18301830 undefined ->
18311831 {keep_state , Data # conn_data {socket = undefined }};
@@ -1879,6 +1879,14 @@ closed(cast, {set_owner, _NewOwner}, #conn_data{pool_pid = PoolPid} = Data)
18791879 % % of lingering through the grace window and being handed out again.
18801880 {stop , normal , Data };
18811881
1882+ closed ({call , From }, _Msg , _Data ) ->
1883+ % % Any other synchronous call arriving during the grace window (request,
1884+ % % request_async, send_headers, body, stream_body, etc.) gets a proper
1885+ % % `{error, closed}` instead of the generic `{error, invalid_state}` from
1886+ % % handle_common. This lets callers distinguish a peer-closed connection
1887+ % % from a misuse of the API.
1888+ {keep_state_and_data , [{reply , From , {error , closed }}]};
1889+
18821890closed (EventType , Event , Data ) ->
18831891 handle_common (EventType , Event , closed , Data ).
18841892
0 commit comments