@@ -72,16 +72,6 @@ const HOOK_CONTEXT_IS_PROCESSING_SYMBOL = Symbol.for(
7272 "@restatedev/restate-sdk/hooks.isProcessing"
7373) ;
7474
75- /**
76- * Builds the Restate handler for an endpoint.
77- *
78- * Responses returned by `handle()` are wrapped via
79- * {@link wrapResponseWithSafety}, which enforces exactly-once `writeHead`,
80- * emits a 500 fallback if `process()` fails before `writeHead` or resolves
81- * without committing a head, and closes the output stream on every path.
82- * Adapters (node, fetch, lambda) can therefore treat transport failures as
83- * logging concerns.
84- */
8575export function createRestateHandler (
8676 endpoint : Endpoint ,
8777 protocolMode : ProtocolMode ,
@@ -94,78 +84,6 @@ export function createRestateHandler(
9484 ) ;
9585}
9686
97- /**
98- * Safety net around a `RestateResponse` returned by `_handle()`, applied
99- * in `RestateHandlerImpl.handle()` before the response reaches any adapter.
100- *
101- * Guarantees to adapters:
102- * - `writeHead` is called exactly once on the success path.
103- * - If `process()` rejects before `writeHead`, a 500 `errorResponse` is
104- * written instead (including input drain).
105- * - If `process()` resolves without calling `writeHead`, same recovery.
106- * - Post-writeHead errors propagate to the adapter for logging — the head
107- * is already committed to the transport and can't be changed.
108- *
109- * Mirrors the existing pattern where `handle()` wraps user errors via
110- * `errorResponse`; this extends that safety net to the `process()` phase.
111- */
112- function wrapResponseWithSafety ( inner : RestateResponse ) : RestateResponse {
113- return {
114- async process ( { inputReader, outputWriter, writeHead, abortSignal } ) {
115- let committed = false ;
116- const safeWriteHead = (
117- statusCode : number ,
118- headers : ResponseHeaders
119- ) : void => {
120- if ( committed ) {
121- throw new Error ( "writeHead() called more than once" ) ;
122- }
123- committed = true ;
124- writeHead ( statusCode , headers ) ;
125- } ;
126-
127- try {
128- try {
129- await inner . process ( {
130- inputReader,
131- outputWriter,
132- writeHead : safeWriteHead ,
133- abortSignal,
134- } ) ;
135- } catch ( e ) {
136- if ( committed ) {
137- // Head already on the wire — nothing structural the adapter can do.
138- throw e ;
139- }
140- await errorResponse ( 500 , ensureError ( e ) . message ) . process ( {
141- inputReader,
142- outputWriter,
143- writeHead,
144- abortSignal,
145- } ) ;
146- return ;
147- }
148-
149- if ( ! committed ) {
150- await errorResponse (
151- 500 ,
152- "Handler did not produce a response head"
153- ) . process ( {
154- inputReader,
155- outputWriter,
156- writeHead,
157- abortSignal,
158- } ) ;
159- }
160- } finally {
161- // Ensure the output stream closes on every path. If it was already
162- // closed (the usual case), close() rejects — which we swallow.
163- await outputWriter . close ( ) . catch ( ( ) => { } ) ;
164- }
165- } ,
166- } ;
167- }
168-
16987/**
17088 * This is the RestateHandler implementation
17189 */
@@ -204,7 +122,7 @@ class RestateHandlerImpl implements RestateHandler {
204122 context ?: AdditionalContext
205123 ) : RestateResponse {
206124 try {
207- return wrapResponseWithSafety ( this . _handle ( request , context ) ) ;
125+ return this . _handle ( request , context ) ;
208126 } catch ( e ) {
209127 const error = ensureError ( e ) ;
210128 (
@@ -216,11 +134,9 @@ class RestateHandlerImpl implements RestateHandler {
216134 ) . error (
217135 "Error while handling request: " + ( error . stack ?? error . message )
218136 ) ;
219- return wrapResponseWithSafety (
220- errorResponse (
221- error instanceof RestateError ? error . code : 500 ,
222- error . message
223- )
137+ return errorResponse (
138+ error instanceof RestateError ? error . code : 500 ,
139+ error . message
224140 ) ;
225141 }
226142 }
0 commit comments