diff --git a/packages/restate-e2e-services/src/proxy.ts b/packages/restate-e2e-services/src/proxy.ts index 74dcdf2c..bf1d5438 100644 --- a/packages/restate-e2e-services/src/proxy.ts +++ b/packages/restate-e2e-services/src/proxy.ts @@ -32,7 +32,7 @@ function rawCall( ctx: restate.Context, request: ProxyRequest ): Promise { - return ctx.genericCall({ + return ctx.call({ service: request.serviceName, method: request.handlerName, key: request.virtualObjectKey, @@ -44,7 +44,7 @@ function rawCall( } function rawSend(ctx: restate.Context, request: ProxyRequest): Promise { - const handle = ctx.genericSend({ + const handle = ctx.send({ service: request.serviceName, method: request.handlerName, key: request.virtualObjectKey, diff --git a/packages/restate-sdk/src/common_api.ts b/packages/restate-sdk/src/common_api.ts index 3b66cab0..5fba9ac3 100644 --- a/packages/restate-sdk/src/common_api.ts +++ b/packages/restate-sdk/src/common_api.ts @@ -18,7 +18,9 @@ export type { WorkflowContext, WorkflowSharedContext, Rand, + Call, GenericCall, + Send, GenericSend, InvocationId, InvocationHandle, diff --git a/packages/restate-sdk/src/context.ts b/packages/restate-sdk/src/context.ts index 1706bff6..e488f082 100644 --- a/packages/restate-sdk/src/context.ts +++ b/packages/restate-sdk/src/context.ts @@ -234,7 +234,7 @@ export type RunOptions = { * This is a generic mechanism to invoke handlers directly by only knowing * the service and handler name, (or key in the case of objects or workflows) */ -export type GenericCall = { +export type Call = { service: string; method: string; parameter: REQ; @@ -245,12 +245,17 @@ export type GenericCall = { idempotencyKey?: string; }; +/** + * @deprecated use {@link Call} + */ +export type GenericCall = Call; + /** * Send a message to an handler directly avoiding restate's type safety checks. * This is a generic mechanism to invoke handlers directly by only knowing * the service and handler name, (or key in the case of objects or workflows) */ -export type GenericSend = { +export type Send = { service: string; method: string; parameter: REQ; @@ -261,6 +266,11 @@ export type GenericSend = { idempotencyKey?: string; }; +/** + * @deprecated use {@link Send} + */ +export type GenericSend = Send; + /** * The context that gives access to all Restate-backed operations, for example * - sending reliable messages / RPC through Restate @@ -569,11 +579,52 @@ export interface Context extends RestateContext { opts?: SendOptions ): SendClient>; + /** + * @deprecated use {@link call} instead + */ genericCall( - call: GenericCall + call: Call ): InvocationPromise; - genericSend(call: GenericSend): InvocationHandle; + /** + * @deprecated use {@link send} instead + */ + genericSend(call: Send): InvocationHandle; + + /** + * Make a request/response RPC to the specified target service. + * + * The RPC goes through Restate and is guaranteed to be reliably delivered. The RPC is also + * journaled for durable execution and will thus not be duplicated when the handler is re-invoked + * for retries or after suspending. + * + * This call will return the result produced by the target handler, or the TerminalError, if the target + * handler finishes with a Terminal Error. + * + * This call is a suspension point: The handler might suspend while awaiting the response and + * resume once the response is available. + * + * @param call send target and options + */ + call(call: Call): InvocationPromise; + + /** + * Send a request to the specified target service. This method effectively behaves + * like enqueuing the message in a message queue. + * + * The message goes through Restate and is guaranteed to be reliably delivered. The RPC is also + * journaled for durable execution and will thus not be duplicated when the handler is re-invoked + * for retries or after suspending. + * + * This returns immediately; the message sending happens asynchronously in the background. + * Despite that, the message is guaranteed to be sent, because the completion of the invocation that + * triggers the send (calls this function) happens logically after the sending. That means that any + * failure where the message does not reach Restate also cannot complete this invocation, and will + * hence recover this handler and (through the durable execution) recover the message to be sent. + * + * @param send send target and options + */ + send(send: Send): InvocationHandle; /** * Returns the raw request that triggered that handler. diff --git a/packages/restate-sdk/src/context_impl.ts b/packages/restate-sdk/src/context_impl.ts index cc6654cf..6a87aae6 100644 --- a/packages/restate-sdk/src/context_impl.ts +++ b/packages/restate-sdk/src/context_impl.ts @@ -14,8 +14,8 @@ import type { ContextDate, DurablePromise, - GenericCall, - GenericSend, + Call, + Send, InvocationHandle, InvocationId, InvocationPromise, @@ -217,13 +217,11 @@ export class ContextImpl implements ObjectContext, WorkflowContext { // --- Calls, background calls, etc // - public genericCall( - call: GenericCall - ): InvocationPromise { + public call(call: Call): InvocationPromise { const requestSerde: Serde = - call.inputSerde ?? (serde.binary as Serde); + call.inputSerde ?? (this.defaultSerde as Serde); const responseSerde: Serde = - call.outputSerde ?? (serde.binary as Serde); + call.outputSerde ?? (this.defaultSerde as Serde); let parameter: Uint8Array; try { @@ -284,10 +282,8 @@ export class ContextImpl implements ObjectContext, WorkflowContext { } } - public genericSend( - send: GenericSend - ): InvocationHandle { - const requestSerde = send.inputSerde ?? (serde.binary as Serde); + public send(send: Send): InvocationHandle { + const requestSerde = send.inputSerde ?? (this.defaultSerde as Serde); let parameter: Uint8Array; try { @@ -345,13 +341,27 @@ export class ContextImpl implements ObjectContext, WorkflowContext { } } - serviceClient({ name }: ServiceDefinitionFrom): Client> { - return makeRpcCallProxy( - (call) => this.genericCall(call), - this.defaultSerde, + public genericCall( + call: Call + ): InvocationPromise { + return this.call({ + ...call, + // Just different defaults here. + inputSerde: call.inputSerde ?? (serde.binary as Serde), + outputSerde: call.outputSerde ?? (serde.binary as Serde), + }); + } - name - ); + public genericSend(send: Send): InvocationHandle { + return this.send({ + ...send, + // Just different defaults here. + inputSerde: send.inputSerde ?? (serde.binary as Serde), + }); + } + + serviceClient({ name }: ServiceDefinitionFrom): Client> { + return makeRpcCallProxy((call) => this.call(call), this.defaultSerde, name); } objectClient( @@ -359,7 +369,7 @@ export class ContextImpl implements ObjectContext, WorkflowContext { key: string ): Client> { return makeRpcCallProxy( - (call) => this.genericCall(call), + (call) => this.call(call), this.defaultSerde, name, key @@ -371,7 +381,7 @@ export class ContextImpl implements ObjectContext, WorkflowContext { key: string ): Client> { return makeRpcCallProxy( - (call) => this.genericCall(call), + (call) => this.call(call), this.defaultSerde, name, key @@ -383,7 +393,7 @@ export class ContextImpl implements ObjectContext, WorkflowContext { opts?: SendOptions ): SendClient> { return makeRpcSendProxy( - (send) => this.genericSend(send), + (send) => this.send(send), this.defaultSerde, name, undefined, @@ -397,7 +407,7 @@ export class ContextImpl implements ObjectContext, WorkflowContext { opts?: SendOptions ): SendClient> { return makeRpcSendProxy( - (send) => this.genericSend(send), + (send) => this.send(send), this.defaultSerde, name, key, @@ -411,7 +421,7 @@ export class ContextImpl implements ObjectContext, WorkflowContext { opts?: SendOptions ): SendClient> { return makeRpcSendProxy( - (send) => this.genericSend(send), + (send) => this.send(send), this.defaultSerde, name, key, diff --git a/packages/restate-sdk/src/types/rpc.ts b/packages/restate-sdk/src/types/rpc.ts index 3732f6dc..df43718d 100644 --- a/packages/restate-sdk/src/types/rpc.ts +++ b/packages/restate-sdk/src/types/rpc.ts @@ -14,8 +14,8 @@ /* eslint-disable @typescript-eslint/ban-types */ import type { Context, - GenericCall, - GenericSend, + Call, + Send, InvocationHandle, InvocationPromise, ObjectContext, @@ -168,7 +168,7 @@ function optsFromArgs(args: unknown[]): { } export const makeRpcCallProxy = ( - genericCall: (call: GenericCall) => Promise, + genericCall: (call: Call) => Promise, defaultSerde: Serde, service: string, key?: string @@ -203,7 +203,7 @@ export const makeRpcCallProxy = ( }; export const makeRpcSendProxy = ( - genericSend: (send: GenericSend) => void, + genericSend: (send: Send) => void, defaultSerde: Serde, service: string, key?: string,