-
Notifications
You must be signed in to change notification settings - Fork 18
Hooks interface & otel integration #663
Copy link
Copy link
Open
Labels
enhancementNew feature or requestNew feature or request
Description
Introduce new hooks interface that will allow us to provide better integration with tracing, and other telemetry libs:
type AttemptResult = {
type: "success"
} | {
type: "retryableError"
error: Error
} | {
type: "terminalError"
error: TerminalError
}
type Hooks = {
// Set this hook to wrap the handler execution. Calling handlerRunner will cause the handler to run.
// Use it to propagate an async context storage.
runInContext?: <T>(handlerRunner: () => Promise<T>) => Promise<T>;
// Called when the attempt completes. Errors thrown inside this function are not propagated back to restate
onAttemptEnd?: (result: AttemptResult) => void;
};
// If the hook provider fails, same rules as handler failures apply:
// * if fails with terminal error, invocation is terminated with terminal error
// * for other failures, it gets retried
type HooksProvider = (ctx: {
serviceName: string;
handlerName: string;
key?: string;
invocationId: string;
request: Request;
}) => Hooks;One can set these HooksProviders on a handler, on a service, or for the whole endpoint, and hooks will compose.
Tracing hooks provider example:
// Example provider: otel tracing
function otelTracing(tracer: Tracer): HooksProvider {
return (ctx) => {
// .... extract parent trace etc ...
const span = tracer.startSpan(`${ctx.serviceName}/${ctx.handlerName}`, {"restate.invocation.id": ctx.invocationId});
return {
runInContext: (handlerRunner) =>
otelContext.with(trace.setSpan(otelContext.active(), span), handlerRunner),
onAttemptEnd: (result) => {
if (result.type === "retryableError") {
span.recordException(result.error);
span.setAttribute("transient", true);
} else if (result.type === "terminalError") {
span.recordException(result.error);
}
span.end();
},
};
};
}
const greeter = restate.service({
name: "Greeter",
handlers: {
greet: async (ctx: restate.Context, name: string) => {
// otel context — via otel API
const span = trace.getActiveSpan();
span?.addEvent("greeting_started");
return `Hello, ${name}!`;
},
},
options: {
hooks: [otelTracing(tracer)]
}
});We could extend these hooks in future to do more things, like hooks on outgoing requests, etc.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request