@hotmeshio/hotmesh
Version:
Serverless Workflow
228 lines (211 loc) • 6.73 kB
text/typescript
import { ProviderTransaction } from './provider';
/** Represents a policy for retrying stream operations based on error codes */
export interface StreamRetryPolicy {
/**
* Key is error code, value is the retry profile.
* Tuple contains: [max retry count, retry type].
* 'x' denotes exponential backoff (default). Only 10, 100, 1000, 10000 are allowed retry intervals.
*/
[key: string]: [number, 'x'?];
}
/** A 3-digit status code representing the outcome of a stream operation */
export type StreamCode = number;
/** Describes the structure of a stream error */
export type StreamError = {
/** Descriptive message of the error */
message: string;
/** Numeric code corresponding to the type of error */
code: number;
/** Optional job identifier, used when communicating errors externally */
job_id?: string;
/** Stack trace of the error if unhandled */
stack?: string;
/** Name of the error if unhandled */
name?: string;
/** Custom user-defined error details */
error?: Record<string, unknown>;
/** True if originating via a standard transition message with an `error` status */
is_stream_error?: boolean;
};
/** Enumerated status values for stream operations */
export enum StreamStatus {
/** Indicates successful completion of the stream operation */
SUCCESS = 'success',
/** Indicates an error occurred during the stream operation */
ERROR = 'error',
/** Indicates the stream operation is still pending */
PENDING = 'pending',
}
export enum StreamDataType {
TIMEHOOK = 'timehook',
WEBHOOK = 'webhook',
AWAIT = 'await',
RESULT = 'result', //await result
WORKER = 'worker',
RESPONSE = 'response', //worker response
TRANSITION = 'transition',
SIGNAL = 'signal',
INTERRUPT = 'interrupt',
}
/** Defines the structure of stream data used when passing stream messages (transitions) */
export interface StreamData {
/** Metadata associated with the stream data */
metadata: {
/** Globally unique identifier for the StreamData message to distinguish `retries` from new 'reentry/cycles' */
guid: string;
/** Workflow/job topic */
topic?: string;
/** Workflow/job ID */
jid?: string;
/** Workflow Generational ID (internal GUID) */
gid?: string;
/** Dimensional address indicating the message routing specifics */
dad?: string;
/** Activity ID */
aid: string;
/** OpenTelemetry Trace identifier */
trc?: string;
/** OpenTelemetry Span identifier */
spn?: string;
/** Current try count, used for retry logic */
try?: number;
/**
* Indicates if the message should wait for a response.
* If explicitly false, the connection is severed immediately
* upon verifying (and returning) the Job ID.
*/
await?: boolean;
};
/** Type of the data being streamed, optional */
type?: StreamDataType;
/** Actual data being transmitted as a record of key-value pairs */
data: Record<string, unknown>;
/** Policies related to retry logic, optional */
policies?: {
retry?: StreamRetryPolicy;
};
/** Status of the stream, default assumed as 'success' */
status?: StreamStatus;
/** HTTP-like status code for the stream, default assumed as 200 */
code?: number;
/** Error stack trace */
stack?: string;
}
/** Extends StreamData for responses, allowing for inheritance of the base properties */
export type StreamDataResponse = StreamData;
export enum StreamRole {
WORKER = 'worker',
ENGINE = 'engine',
SYSTEM = 'system', //reserved for system use (i.e, if worker or engine fails)
}
/**
* Represents a type for messages that have been reclaimed from a stream.
* Each item is a tuple containing a messageId and its details.
*/
export type ReclaimedMessageType = [
/** The stream ID, typically formatted as `<timestamp>-<count>` */
messageId: string,
/** Details of the message, consisting of a key and its value */
details: [
/** Key is always 'message' */
key: string,
/** Value is a stringified representation of StreamData */
value: string,
],
][];
/** Configuration parameters for a stream */
export type RouterConfig = {
/** Namespace under which the stream operates */
namespace: string;
/** Application identifier */
appId: string;
/** Globally unique identifier for the stream */
guid: string;
/** Role associated with the stream */
role: StreamRole;
/** Default throttle (read from KeyType.THROTTLE_RATE) */
throttle: number;
/** Optional topic for the stream */
topic?: string;
/** Delay before a message can be reclaimed, defaults to 60,000 milliseconds */
reclaimDelay?: number;
/** Maximum number of reclaims allowed, defaults to 3. Values greater throw an error */
reclaimCount?: number;
/** if true, will not process stream messages; default true */
readonly?: boolean;
};
export type StreamProviderType =
| 'redis'
| 'ioredis'
| 'postgres'
| 'nats'
| 'sqs';
export interface StreamConfig {
// Common configuration
provider?: StreamProviderType;
namespace?: string;
appId?: string;
maxRetries?: number;
batchSize?: number;
timeout?: number;
// Provider-specific configurations
redis?: {
claimTimeout?: number;
blockingTimeout?: number;
minIdleTime?: number;
};
postgres?: {
pollInterval?: number;
vacuumInterval?: number;
partitionInterval?: 'daily' | 'weekly' | 'monthly';
cleanupInterval?: number;
};
nats?: {
jetstream?: boolean;
durableName?: string;
deliverPolicy?: 'all' | 'last' | 'new' | 'byStartSequence' | 'byStartTime';
ackWait?: number;
};
sqs?: {
deadLetterQueue?: string;
visibilityTimeout?: number;
waitTimeSeconds?: number;
messageRetentionPeriod?: number;
dlqArn?: string;
};
}
export interface StreamMessage {
id: string;
data: StreamData;
metadata?: StreamMessageMetadata;
}
export interface StreamMessageMetadata {
timestamp?: number;
stream?: string;
groupName?: string;
consumerName?: string;
retryCount?: number;
deliveryTime?: number;
originalMessageId?: string;
[key: string]: any; // For provider-specific metadata
}
export interface StreamStats {
messageCount: number;
consumerCount?: number;
bytesInMemory?: number;
oldestMessageTimestamp?: number;
pendingMessages?: number;
deadLetterQueueMessageCount?: number;
averageProcessingTime?: number;
lastErrorTimestamp?: number;
lastErrorMessage?: string;
[key: string]: any; // For provider-specific stats
}
/**
* When publishing a message to the stream, the configuration
* can include a transaction object to execute the operation
* atomically.
*/
export interface PublishMessageConfig {
transaction?: ProviderTransaction;
}