UNPKG

@temporalio/client

Version:
328 lines (327 loc) 14.3 kB
import { AsyncLocalStorage } from 'node:async_hooks'; import * as grpc from '@grpc/grpc-js'; import type * as proto from 'protobufjs'; import { TLSConfig } from '@temporalio/common/lib/internal-non-workflow'; import { Duration } from '@temporalio/common/lib/time'; import { CallContext, HealthService, Metadata, OperatorService, TestService, WorkflowService } from './types'; /** * gRPC and Temporal Server connection options */ export interface ConnectionOptions { /** * The address of the Temporal server to connect to, in `hostname:port` format. * * Port defaults to 7233. Raw IPv6 addresses must be wrapped in square brackets (e.g. `[ipv6]:port`). * * @default localhost:7233 */ address?: string; /** * TLS configuration. Pass a falsy value to use a non-encrypted connection, * or `true` or `{}` to connect with TLS without any customization. * * For advanced scenario, a prebuilt {@link grpc.ChannelCredentials} object * may instead be specified using the {@link credentials} property. * * Either {@link credentials} or this may be specified for configuring TLS * * @default TLS is disabled */ tls?: TLSConfig | boolean | null; /** * gRPC channel credentials. * * `ChannelCredentials` are things like SSL credentials that can be used to secure a connection. * There may be only one `ChannelCredentials`. They can be created using some of the factory * methods defined {@link https://grpc.github.io/grpc/node/grpc.credentials.html | here} * * Specifying a prebuilt `ChannelCredentials` should only be required for advanced use cases. * For simple TLS use cases, using the {@link tls} property is recommended. To register * `CallCredentials` (eg. metadata-based authentication), use the {@link callCredentials} property. * * Either {@link tls} or this may be specified for configuring TLS */ credentials?: grpc.ChannelCredentials; /** * gRPC call credentials. * * `CallCredentials` generaly modify metadata; they can be attached to a connection to affect all method * calls made using that connection. They can be created using some of the factory methods defined * {@link https://grpc.github.io/grpc/node/grpc.credentials.html | here} * * If `callCredentials` are specified, they will be composed with channel credentials * (either the one created implicitely by using the {@link tls} option, or the one specified * explicitly through {@link credentials}). Notice that gRPC doesn't allow registering * `callCredentials` on insecure connections. */ callCredentials?: grpc.CallCredentials[]; /** * GRPC Channel arguments * * @see option descriptions {@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html | here} * * By default the SDK sets the following keepalive arguments: * * ``` * grpc.keepalive_permit_without_calls: 1 * grpc.keepalive_time_ms: 30_000 * grpc.keepalive_timeout_ms: 15_000 * ``` * * To opt-out of keepalive, override these keys with `undefined`. */ channelArgs?: grpc.ChannelOptions; /** * {@link https://grpc.github.io/grpc/node/module-src_client_interceptors.html | gRPC interceptors} which will be * applied to every RPC call performed by this connection. By default, an interceptor will be included which * automatically retries retryable errors. If you do not wish to perform automatic retries, set this to an empty list * (or a list with your own interceptors). If you want to add your own interceptors while keeping the default retry * behavior, add this to your list of interceptors: `makeGrpcRetryInterceptor(defaultGrpcRetryOptions())`. See: * * - {@link makeGrpcRetryInterceptor} * - {@link defaultGrpcRetryOptions} */ interceptors?: grpc.Interceptor[]; /** * Optional mapping of gRPC metadata (HTTP headers) to send with each request to the server. * Setting the `Authorization` header is mutually exclusive with the {@link apiKey} option. * * In order to dynamically set metadata, use {@link Connection.withMetadata} */ metadata?: Metadata; /** * API key for Temporal. This becomes the "Authorization" HTTP header with "Bearer " prepended. * This is mutually exclusive with the `Authorization` header in {@link ConnectionOptions.metadata}. * * You may provide a static string or a callback. Also see {@link Connection.withApiKey} or * {@link Connection.setApiKey} */ apiKey?: string | (() => string); /** * Milliseconds to wait until establishing a connection with the server. * * Used either when connecting eagerly with {@link Connection.connect} or * calling {@link Connection.ensureConnected}. * * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string} * @default 10 seconds */ connectTimeout?: Duration; } export type ConnectionOptionsWithDefaults = Required<Omit<ConnectionOptions, 'tls' | 'connectTimeout' | 'callCredentials' | 'apiKey'>> & { connectTimeoutMs: number; }; /** * A symbol used to attach extra, SDK-internal connection options. * * @internal * @hidden */ export declare const InternalConnectionOptionsSymbol: unique symbol; export type InternalConnectionOptions = ConnectionOptions & { [InternalConnectionOptionsSymbol]?: { /** * Indicate whether the `TestService` should be enabled on this connection. This is set to true * on connections created internally by `TestWorkflowEnvironment.createTimeSkipping()`. */ supportsTestService?: boolean; }; }; export declare const LOCAL_TARGET = "localhost:7233"; export interface RPCImplOptions { serviceName: string; client: grpc.Client; callContextStorage: AsyncLocalStorage<CallContext>; interceptors?: grpc.Interceptor[]; staticMetadata: Metadata; apiKeyFnRef: { fn?: () => string; }; } export interface ConnectionCtorOptions { readonly options: ConnectionOptionsWithDefaults; readonly client: grpc.Client; /** * Raw gRPC access to the Temporal service. * * **NOTE**: The namespace provided in {@link options} is **not** automatically set on requests made to the service. */ readonly workflowService: WorkflowService; /** * Raw gRPC access to the Temporal {@link https://github.com/temporalio/api/blob/ddf07ab9933e8230309850e3c579e1ff34b03f53/temporal/api/operatorservice/v1/service.proto | operator service}. */ readonly operatorService: OperatorService; /** * Raw gRPC access to the Temporal test service. * * Will be `undefined` if connected to a server that does not support the test service. */ readonly testService: TestService | undefined; /** * Raw gRPC access to the standard gRPC {@link https://github.com/grpc/grpc/blob/92f58c18a8da2728f571138c37760a721c8915a2/doc/health-checking.md | health service}. */ readonly healthService: HealthService; readonly callContextStorage: AsyncLocalStorage<CallContext>; readonly apiKeyFnRef: { fn?: () => string; }; } /** * Client connection to the Temporal Server * * ⚠️ Connections are expensive to construct and should be reused. * Make sure to {@link close} any unused connections to avoid leaking resources. */ export declare class Connection { /** * @internal */ static readonly Client: grpc.ServiceClientConstructor; readonly options: ConnectionOptionsWithDefaults; protected readonly client: grpc.Client; /** * Used to ensure `ensureConnected` is called once. */ protected connectPromise?: Promise<void>; /** * Raw gRPC access to Temporal Server's {@link * https://github.com/temporalio/api/blob/master/temporal/api/workflowservice/v1/service.proto | Workflow service} */ readonly workflowService: WorkflowService; /** * Raw gRPC access to Temporal Server's * {@link https://github.com/temporalio/api/blob/master/temporal/api/operatorservice/v1/service.proto | Operator service} * * The Operator Service API defines how Temporal SDKs and other clients interact with the Temporal * server to perform administrative functions like registering a search attribute or a namespace. * * This Service API is NOT compatible with Temporal Cloud. Attempt to use it against a Temporal * Cloud namespace will result in gRPC `unauthorized` error. */ readonly operatorService: OperatorService; /** * Raw gRPC access to the Temporal test service. * * Will be `undefined` if connected to a server that does not support the test service. */ readonly testService: TestService | undefined; /** * Raw gRPC access to the standard gRPC {@link https://github.com/grpc/grpc/blob/92f58c18a8da2728f571138c37760a721c8915a2/doc/health-checking.md | health service}. */ readonly healthService: HealthService; readonly callContextStorage: AsyncLocalStorage<CallContext>; private readonly apiKeyFnRef; protected static createCtorOptions(options?: ConnectionOptions): ConnectionCtorOptions; /** * Ensure connection can be established. * * Does not need to be called if you use {@link connect}. * * This method's result is memoized to ensure it runs only once. * * Calls {@link proto.temporal.api.workflowservice.v1.WorkflowService.getSystemInfo} internally. */ ensureConnected(): Promise<void>; /** * Create a lazy `Connection` instance. * * This method does not verify connectivity with the server. We recommend using {@link connect} instead. */ static lazy(options?: ConnectionOptions): Connection; /** * Establish a connection with the server and return a `Connection` instance. * * This is the preferred method of creating connections as it verifies connectivity by calling * {@link ensureConnected}. */ static connect(options?: ConnectionOptions): Promise<Connection>; protected constructor({ options, client, workflowService, operatorService, testService, healthService, callContextStorage, apiKeyFnRef, }: ConnectionCtorOptions); protected static generateRPCImplementation({ serviceName, client, callContextStorage, interceptors, staticMetadata, apiKeyFnRef, }: RPCImplOptions): proto.RPCImpl; /** * Set a deadline for any service requests executed in `fn`'s scope. * * The deadline is a point in time after which any pending gRPC request will be considered as failed; * this will locally result in the request call throwing a {@link grpc.ServiceError|ServiceError} * with code {@link grpc.status.DEADLINE_EXCEEDED|DEADLINE_EXCEEDED}; see {@link isGrpcDeadlineError}. * * It is stronly recommended to explicitly set deadlines. If no deadline is set, then it is * possible for the client to end up waiting forever for a response. * * @param deadline a point in time after which the request will be considered as failed; either a * Date object, or a number of milliseconds since the Unix epoch (UTC). * @returns the value returned from `fn` * * @see https://grpc.io/docs/guides/deadlines/ */ withDeadline<ReturnType>(deadline: number | Date, fn: () => Promise<ReturnType>): Promise<ReturnType>; /** * Set an {@link AbortSignal} that, when aborted, cancels any ongoing service requests executed in * `fn`'s scope. This will locally result in the request call throwing a {@link grpc.ServiceError|ServiceError} * with code {@link grpc.status.CANCELLED|CANCELLED}; see {@link isGrpcCancelledError}. * * This method is only a convenience wrapper around {@link Connection.withAbortSignal}. * * @example * * ```ts * const ctrl = new AbortController(); * setTimeout(() => ctrl.abort(), 10_000); * // 👇 throws if incomplete by the timeout. * await conn.withAbortSignal(ctrl.signal, () => client.workflow.execute(myWorkflow, options)); * ``` * * @returns value returned from `fn` * * @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal */ withAbortSignal<ReturnType>(abortSignal: AbortSignal, fn: () => Promise<ReturnType>): Promise<ReturnType>; /** * Set metadata for any service requests executed in `fn`'s scope. * * The provided metadata is merged on top of any existing metadata in current scope, including metadata provided in * {@link ConnectionOptions.metadata}. * * @returns value returned from `fn` * * @example * * ```ts * const workflowHandle = await conn.withMetadata({ apiKey: 'secret' }, () => * conn.withMetadata({ otherKey: 'set' }, () => client.start(options))) * ); * ``` */ withMetadata<ReturnType>(metadata: Metadata, fn: () => Promise<ReturnType>): Promise<ReturnType>; /** * Set the apiKey for any service requests executed in `fn`'s scope (thus changing the `Authorization` header). * * @returns value returned from `fn` * * @example * * ```ts * const workflowHandle = await conn.withApiKey('secret', () => * conn.withMetadata({ otherKey: 'set' }, () => client.start(options))) * ); * ``` */ withApiKey<ReturnType>(apiKey: string, fn: () => Promise<ReturnType>): Promise<ReturnType>; /** * Set the {@link ConnectionOptions.apiKey} for all subsequent requests. A static string or a * callback function may be provided. */ setApiKey(apiKey: string | (() => string)): void; /** * Wait for successful connection to the server. * * @see https://grpc.github.io/grpc/node/grpc.Client.html#waitForReady__anchor */ protected untilReady(deadline: number): Promise<void>; /** * Close the underlying gRPC client. * * Make sure to call this method to ensure proper resource cleanup. */ close(): Promise<void>; private withNamespaceHeaderInjector; }