@hatchet-dev/typescript-sdk 1.35.0 → 1.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/clients/dispatcher/action-listener.js +0 -2
- package/clients/rest/generated/Api.d.ts +27 -1
- package/clients/rest/generated/Api.js +20 -0
- package/clients/rest/generated/data-contracts.d.ts +4 -0
- package/package.json +1 -1
- package/protoc/v1/streams.d.ts +34 -0
- package/protoc/v1/streams.js +279 -5
- package/protoc-es/v1/streams_pb.d.ts +79 -0
- package/protoc-es/v1/streams_pb.js +12 -2
- package/v1/client/features/streams.d.ts +22 -0
- package/v1/client/features/streams.js +93 -13
- package/v1/client/worker/worker-internal.js +9 -7
- package/v1/examples/durable-streams/benchmark.d.ts +34 -0
- package/v1/examples/durable-streams/benchmark.js +120 -0
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/v1/examples/durable-streams/publish-latency.d.ts +0 -15
- package/v1/examples/durable-streams/publish-latency.js +0 -50
|
@@ -225,8 +225,6 @@ class ActionListener {
|
|
|
225
225
|
}
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
|
-
// Leaves the heartbeat running: tasks that are already in flight still need
|
|
229
|
-
// the engine to see this worker as alive until they finish.
|
|
230
228
|
stopStream() {
|
|
231
229
|
this.done = true;
|
|
232
230
|
// Abort the gRPC stream to immediately cancel the generator
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { APIErrors, APIMeta, AcceptInviteRequest, BulkCreateEventRequest, CancelEventRequest, CreateAPITokenRequest, CreateAPITokenResponse, CreateCronWorkflowTriggerRequest, CreateEventRequest, CreateSNSIntegrationRequest, CreateTenantAlertEmailGroupRequest, CreateTenantInviteRequest, CreateTenantRequest, CronWorkflows, CronWorkflowsList, CronWorkflowsOrderByField, Event, EventData, EventKey, EventKeyList, EventList, EventOrderByDirection, EventOrderByField, EventSearch, Events, FeatureFlagEvaluationResult, FeatureFlagId, ListAPIMetaIntegration, ListAPITokensResponse, ListSNSIntegrations, ListSlackWebhooks, OtelSpanList, RateLimitList, RateLimitOrderByDirection, RateLimitOrderByField, RejectInviteRequest, ReplayEventRequest, ReplayWorkflowRunsRequest, ReplayWorkflowRunsResponse, RerunStepRunRequest, SNSIntegration, ScheduleWorkflowRunRequest, ScheduledRunStatus, ScheduledWorkflows, ScheduledWorkflowsBulkDeleteRequest, ScheduledWorkflowsBulkDeleteResponse, ScheduledWorkflowsBulkUpdateRequest, ScheduledWorkflowsBulkUpdateResponse, ScheduledWorkflowsList, ScheduledWorkflowsOrderByField, StepRun, StepRunArchiveList, StepRunEventList, TaskStats, Tenant, TenantAlertEmailGroup, TenantAlertEmailGroupList, TenantAlertingSettings, TenantInvite, TenantInviteList, TenantMember, TenantMemberList, TenantQueueMetrics, TenantResourcePolicy, TenantStepRunQueueMetrics, TriggerRunResult, TriggerWorkflowRunRequest, UpdateCronWorkflowTriggerRequest, UpdateScheduledWorkflowRunRequest, UpdateTenantAlertEmailGroupRequest, UpdateTenantInviteRequest, UpdateTenantMemberRequest, UpdateTenantRequest, UpdateWorkerRequest, User, UserChangePasswordRequest, UserLoginRequest, UserRegisterRequest, UserTenantMembershipsList, V1AdditionalMetadataOperator, V1BranchDurableTaskRequest, V1BranchDurableTaskResponse, V1CELDebugRequest, V1CELDebugResponse, V1CancelTaskRequest, V1CancelledTasks, V1CreateFilterRequest, V1CreateWebhookRequest, V1DagChildren, V1DurableEventLogList, V1Event, V1EventList, V1Filter, V1FilterList, V1LogLineLevel, V1LogLineList, V1LogLineOrderByDirection, V1LogsPointMetrics, V1ReplayTaskRequest, V1ReplayedTasks, V1RestoreTaskResponse, V1RunningFilter, V1TaskEventList, V1TaskPointMetrics, V1TaskRunMetrics, V1TaskStatus, V1TaskSummary, V1TaskSummaryList, V1TaskTimingList, V1TriggerWorkflowRunRequest, V1UpdateFilterRequest, V1UpdateWebhookRequest, V1Webhook, V1WebhookList, V1WebhookResponse, V1WebhookSourceName, V1WorkflowRunDetails, V1WorkflowRunDisplayNameList, V1WorkflowRunExternalIdList, WebhookWorkerCreateRequest, WebhookWorkerCreated, WebhookWorkerListResponse, WebhookWorkerRequestListResponse, Worker, WorkerList, WorkerStatus, Workflow, WorkflowID, WorkflowKindList, WorkflowList, WorkflowMetrics, WorkflowRun, WorkflowRunList, WorkflowRunOrderByDirection, WorkflowRunOrderByField, WorkflowRunShape, WorkflowRunStatus, WorkflowRunStatusList, WorkflowRunsCancelRequest, WorkflowRunsMetrics, WorkflowUpdateRequest, WorkflowVersion, WorkflowWorkersCount } from './data-contracts';
|
|
1
|
+
import { APIErrors, APIMeta, AcceptInviteRequest, BulkCreateEventRequest, CancelEventRequest, CreateAPITokenRequest, CreateAPITokenResponse, CreateCronWorkflowTriggerRequest, CreateEventRequest, CreateSNSIntegrationRequest, CreateTenantAlertEmailGroupRequest, CreateTenantInviteRequest, CreateTenantRequest, CronWorkflows, CronWorkflowsList, CronWorkflowsOrderByField, Event, EventData, EventKey, EventKeyList, EventList, EventOrderByDirection, EventOrderByField, EventSearch, Events, FeatureFlagEvaluationResult, FeatureFlagId, ListAPIMetaIntegration, ListAPITokensResponse, ListSNSIntegrations, ListSlackWebhooks, OtelSpanList, RateLimitList, RateLimitOrderByDirection, RateLimitOrderByField, RejectInviteRequest, ReplayEventRequest, ReplayWorkflowRunsRequest, ReplayWorkflowRunsResponse, RerunStepRunRequest, SNSIntegration, ScheduleWorkflowRunRequest, ScheduledRunStatus, ScheduledWorkflows, ScheduledWorkflowsBulkDeleteRequest, ScheduledWorkflowsBulkDeleteResponse, ScheduledWorkflowsBulkUpdateRequest, ScheduledWorkflowsBulkUpdateResponse, ScheduledWorkflowsList, ScheduledWorkflowsOrderByField, StepRun, StepRunArchiveList, StepRunEventList, TaskStats, Tenant, TenantAlertEmailGroup, TenantAlertEmailGroupList, TenantAlertingSettings, TenantInvite, TenantInviteList, TenantMember, TenantMemberList, TenantQueueMetrics, TenantResourcePolicy, TenantStepRunQueueMetrics, TriggerRunResult, TriggerWorkflowRunRequest, UpdateCronWorkflowTriggerRequest, UpdateScheduledWorkflowRunRequest, UpdateTenantAlertEmailGroupRequest, UpdateTenantInviteRequest, UpdateTenantMemberRequest, UpdateTenantRequest, UpdateWorkerRequest, User, UserChangePasswordRequest, UserLoginRequest, UserRegisterRequest, UserTenantMembershipsList, V1AdditionalMetadataOperator, V1BranchDurableTaskRequest, V1BranchDurableTaskResponse, V1CELDebugRequest, V1CELDebugResponse, V1CancelTaskRequest, V1CancelledTasks, V1CreateFilterRequest, V1CreateWebhookRequest, V1DagChildren, V1DurableEventLogList, V1Event, V1EventList, V1Filter, V1FilterList, V1LogLineLevel, V1LogLineList, V1LogLineOrderByDirection, V1LogsPointMetrics, V1ReplayTaskRequest, V1ReplayedTasks, V1RestoreTaskResponse, V1RunningFilter, V1StreamPayloadRef, V1TaskEventList, V1TaskPointMetrics, V1TaskRunMetrics, V1TaskStatus, V1TaskSummary, V1TaskSummaryList, V1TaskTimingList, V1TriggerWorkflowRunRequest, V1UpdateFilterRequest, V1UpdateWebhookRequest, V1Webhook, V1WebhookList, V1WebhookResponse, V1WebhookSourceName, V1WorkflowRunDetails, V1WorkflowRunDisplayNameList, V1WorkflowRunExternalIdList, WebhookWorkerCreateRequest, WebhookWorkerCreated, WebhookWorkerListResponse, WebhookWorkerRequestListResponse, Worker, WorkerList, WorkerStatus, Workflow, WorkflowID, WorkflowKindList, WorkflowList, WorkflowMetrics, WorkflowRun, WorkflowRunList, WorkflowRunOrderByDirection, WorkflowRunOrderByField, WorkflowRunShape, WorkflowRunStatus, WorkflowRunStatusList, WorkflowRunsCancelRequest, WorkflowRunsMetrics, WorkflowUpdateRequest, WorkflowVersion, WorkflowWorkersCount } from './data-contracts';
|
|
2
2
|
import { HttpClient, RequestParams } from './http-client';
|
|
3
3
|
export declare class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
|
|
4
4
|
/**
|
|
@@ -341,6 +341,32 @@ export declare class Api<SecurityDataType = unknown> extends HttpClient<Security
|
|
|
341
341
|
*/
|
|
342
342
|
limit?: number;
|
|
343
343
|
}, params?: RequestParams) => Promise<import("axios").AxiosResponse<V1DurableEventLogList, any, {}>>;
|
|
344
|
+
/**
|
|
345
|
+
* @description Get a durable stream payload uploaded ahead of its publish, by the payload_ref of the message that references it.
|
|
346
|
+
*
|
|
347
|
+
* @tags Streams
|
|
348
|
+
* @name V1StreamPayloadGet
|
|
349
|
+
* @summary Get stream payload
|
|
350
|
+
* @request GET:/api/v1/stable/tenants/{tenant}/streams/payloads
|
|
351
|
+
* @secure
|
|
352
|
+
*/
|
|
353
|
+
v1StreamPayloadGet: (tenant: string, query: {
|
|
354
|
+
/** The payload_ref of the stream message */
|
|
355
|
+
ref: string;
|
|
356
|
+
}, params?: RequestParams) => Promise<import("axios").AxiosResponse<File, any, {}>>;
|
|
357
|
+
/**
|
|
358
|
+
* @description Upload a payload too large for a gRPC publish, then publish the message with the returned ref as its payload_ref.
|
|
359
|
+
*
|
|
360
|
+
* @tags Streams
|
|
361
|
+
* @name V1StreamPayloadUpload
|
|
362
|
+
* @summary Upload stream payload
|
|
363
|
+
* @request POST:/api/v1/stable/tenants/{tenant}/streams/payloads
|
|
364
|
+
* @secure
|
|
365
|
+
*/
|
|
366
|
+
v1StreamPayloadUpload: (tenant: string, data: {
|
|
367
|
+
/** @format binary */
|
|
368
|
+
payload: File;
|
|
369
|
+
}, params?: RequestParams) => Promise<import("axios").AxiosResponse<V1StreamPayloadRef, any, {}>>;
|
|
344
370
|
/**
|
|
345
371
|
* @description Get a workflow run and its metadata to display on the "detail" page
|
|
346
372
|
*
|
|
@@ -166,6 +166,26 @@ class Api extends http_client_1.HttpClient {
|
|
|
166
166
|
* @secure
|
|
167
167
|
*/
|
|
168
168
|
this.v1DurableTaskEventLogList = (tenant, durableTask, query, params = {}) => this.request(Object.assign({ path: `/api/v1/stable/tenants/${tenant}/durable-tasks/${durableTask}`, method: 'GET', query: query, secure: true, format: 'json' }, params));
|
|
169
|
+
/**
|
|
170
|
+
* @description Get a durable stream payload uploaded ahead of its publish, by the payload_ref of the message that references it.
|
|
171
|
+
*
|
|
172
|
+
* @tags Streams
|
|
173
|
+
* @name V1StreamPayloadGet
|
|
174
|
+
* @summary Get stream payload
|
|
175
|
+
* @request GET:/api/v1/stable/tenants/{tenant}/streams/payloads
|
|
176
|
+
* @secure
|
|
177
|
+
*/
|
|
178
|
+
this.v1StreamPayloadGet = (tenant, query, params = {}) => this.request(Object.assign({ path: `/api/v1/stable/tenants/${tenant}/streams/payloads`, method: 'GET', query: query, secure: true }, params));
|
|
179
|
+
/**
|
|
180
|
+
* @description Upload a payload too large for a gRPC publish, then publish the message with the returned ref as its payload_ref.
|
|
181
|
+
*
|
|
182
|
+
* @tags Streams
|
|
183
|
+
* @name V1StreamPayloadUpload
|
|
184
|
+
* @summary Upload stream payload
|
|
185
|
+
* @request POST:/api/v1/stable/tenants/{tenant}/streams/payloads
|
|
186
|
+
* @secure
|
|
187
|
+
*/
|
|
188
|
+
this.v1StreamPayloadUpload = (tenant, data, params = {}) => this.request(Object.assign({ path: `/api/v1/stable/tenants/${tenant}/streams/payloads`, method: 'POST', body: data, secure: true, type: http_client_1.ContentType.FormData, format: 'json' }, params));
|
|
169
189
|
/**
|
|
170
190
|
* @description Get a workflow run and its metadata to display on the "detail" page
|
|
171
191
|
*
|
|
@@ -766,6 +766,10 @@ export interface V1DurableEventLogEntry {
|
|
|
766
766
|
taskDisplayName: string;
|
|
767
767
|
}
|
|
768
768
|
export type V1DurableEventLogList = V1DurableEventLogEntry[];
|
|
769
|
+
export interface V1StreamPayloadRef {
|
|
770
|
+
/** Publish the message with this as its payload_ref */
|
|
771
|
+
ref: string;
|
|
772
|
+
}
|
|
769
773
|
export interface OtelSpan {
|
|
770
774
|
traceId: string;
|
|
771
775
|
spanId: string;
|
package/package.json
CHANGED
package/protoc/v1/streams.d.ts
CHANGED
|
@@ -7,6 +7,11 @@ export interface PublishStreamMessageRequest {
|
|
|
7
7
|
payload: Uint8Array;
|
|
8
8
|
producerId: string;
|
|
9
9
|
producerSeq: number;
|
|
10
|
+
/**
|
|
11
|
+
* instead of payload: a ref returned by the stream payload upload endpoint,
|
|
12
|
+
* for payloads too large for one gRPC message
|
|
13
|
+
*/
|
|
14
|
+
payloadRef: string;
|
|
10
15
|
}
|
|
11
16
|
export interface PublishStreamMessageResponse {
|
|
12
17
|
}
|
|
@@ -24,12 +29,31 @@ export interface StreamEntry {
|
|
|
24
29
|
payload: Uint8Array;
|
|
25
30
|
cursor: string;
|
|
26
31
|
createdAt: Date | undefined;
|
|
32
|
+
/** instead of payload: fetch it from the stream payload endpoint by this ref */
|
|
33
|
+
payloadRef: string;
|
|
34
|
+
}
|
|
35
|
+
export interface GetStreamTopicMetadataRequest {
|
|
36
|
+
namespace: string;
|
|
37
|
+
topic: string;
|
|
38
|
+
}
|
|
39
|
+
/** Counts and the latest message cover only what's within the tenant's retention. */
|
|
40
|
+
export interface StreamTopicMetadata {
|
|
41
|
+
namespace: string;
|
|
42
|
+
topic: string;
|
|
43
|
+
tenantId: string;
|
|
44
|
+
/** resumes a subscription after the newest retained message; unset when none is retained */
|
|
45
|
+
latestCursor?: string | undefined;
|
|
46
|
+
messageCount: number;
|
|
47
|
+
/** when the newest retained message was stored; unset when none is retained */
|
|
48
|
+
lastPublishedAt: Date | undefined;
|
|
27
49
|
}
|
|
28
50
|
export declare const PublishStreamMessageRequest: MessageFns<PublishStreamMessageRequest>;
|
|
29
51
|
export declare const PublishStreamMessageResponse: MessageFns<PublishStreamMessageResponse>;
|
|
30
52
|
export declare const SubscribeStreamRequest: MessageFns<SubscribeStreamRequest>;
|
|
31
53
|
export declare const StreamMessage: MessageFns<StreamMessage>;
|
|
32
54
|
export declare const StreamEntry: MessageFns<StreamEntry>;
|
|
55
|
+
export declare const GetStreamTopicMetadataRequest: MessageFns<GetStreamTopicMetadataRequest>;
|
|
56
|
+
export declare const StreamTopicMetadata: MessageFns<StreamTopicMetadata>;
|
|
33
57
|
export type V1StreamsDefinition = typeof V1StreamsDefinition;
|
|
34
58
|
export declare const V1StreamsDefinition: {
|
|
35
59
|
readonly name: "V1Streams";
|
|
@@ -51,15 +75,25 @@ export declare const V1StreamsDefinition: {
|
|
|
51
75
|
readonly responseStream: true;
|
|
52
76
|
readonly options: {};
|
|
53
77
|
};
|
|
78
|
+
readonly getTopicMetadata: {
|
|
79
|
+
readonly name: "GetTopicMetadata";
|
|
80
|
+
readonly requestType: typeof GetStreamTopicMetadataRequest;
|
|
81
|
+
readonly requestStream: false;
|
|
82
|
+
readonly responseType: typeof StreamTopicMetadata;
|
|
83
|
+
readonly responseStream: false;
|
|
84
|
+
readonly options: {};
|
|
85
|
+
};
|
|
54
86
|
};
|
|
55
87
|
};
|
|
56
88
|
export interface V1StreamsServiceImplementation<CallContextExt = {}> {
|
|
57
89
|
publish(request: PublishStreamMessageRequest, context: CallContext & CallContextExt): Promise<DeepPartial<PublishStreamMessageResponse>>;
|
|
58
90
|
subscribe(request: SubscribeStreamRequest, context: CallContext & CallContextExt): ServerStreamingMethodResult<DeepPartial<StreamMessage>>;
|
|
91
|
+
getTopicMetadata(request: GetStreamTopicMetadataRequest, context: CallContext & CallContextExt): Promise<DeepPartial<StreamTopicMetadata>>;
|
|
59
92
|
}
|
|
60
93
|
export interface V1StreamsClient<CallOptionsExt = {}> {
|
|
61
94
|
publish(request: DeepPartial<PublishStreamMessageRequest>, options?: CallOptions & CallOptionsExt): Promise<PublishStreamMessageResponse>;
|
|
62
95
|
subscribe(request: DeepPartial<SubscribeStreamRequest>, options?: CallOptions & CallOptionsExt): AsyncIterable<StreamMessage>;
|
|
96
|
+
getTopicMetadata(request: DeepPartial<GetStreamTopicMetadataRequest>, options?: CallOptions & CallOptionsExt): Promise<StreamTopicMetadata>;
|
|
63
97
|
}
|
|
64
98
|
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
|
|
65
99
|
export type DeepPartial<T> = T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? {
|
package/protoc/v1/streams.js
CHANGED
|
@@ -5,13 +5,20 @@
|
|
|
5
5
|
// protoc v3.19.1
|
|
6
6
|
// source: v1/streams.proto
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.V1StreamsDefinition = exports.StreamEntry = exports.StreamMessage = exports.SubscribeStreamRequest = exports.PublishStreamMessageResponse = exports.PublishStreamMessageRequest = exports.protobufPackage = void 0;
|
|
8
|
+
exports.V1StreamsDefinition = exports.StreamTopicMetadata = exports.GetStreamTopicMetadataRequest = exports.StreamEntry = exports.StreamMessage = exports.SubscribeStreamRequest = exports.PublishStreamMessageResponse = exports.PublishStreamMessageRequest = exports.protobufPackage = void 0;
|
|
9
9
|
/* eslint-disable */
|
|
10
10
|
const wire_1 = require("@bufbuild/protobuf/wire");
|
|
11
11
|
const timestamp_1 = require("../google/protobuf/timestamp");
|
|
12
12
|
exports.protobufPackage = 'v1';
|
|
13
13
|
function createBasePublishStreamMessageRequest() {
|
|
14
|
-
return {
|
|
14
|
+
return {
|
|
15
|
+
namespace: '',
|
|
16
|
+
topic: '',
|
|
17
|
+
payload: new Uint8Array(0),
|
|
18
|
+
producerId: '',
|
|
19
|
+
producerSeq: 0,
|
|
20
|
+
payloadRef: '',
|
|
21
|
+
};
|
|
15
22
|
}
|
|
16
23
|
exports.PublishStreamMessageRequest = {
|
|
17
24
|
encode(message, writer = new wire_1.BinaryWriter()) {
|
|
@@ -30,6 +37,9 @@ exports.PublishStreamMessageRequest = {
|
|
|
30
37
|
if (message.producerSeq !== 0) {
|
|
31
38
|
writer.uint32(40).int64(message.producerSeq);
|
|
32
39
|
}
|
|
40
|
+
if (message.payloadRef !== '') {
|
|
41
|
+
writer.uint32(50).string(message.payloadRef);
|
|
42
|
+
}
|
|
33
43
|
return writer;
|
|
34
44
|
},
|
|
35
45
|
decode(input, length) {
|
|
@@ -74,6 +84,13 @@ exports.PublishStreamMessageRequest = {
|
|
|
74
84
|
message.producerSeq = longToNumber(reader.int64());
|
|
75
85
|
continue;
|
|
76
86
|
}
|
|
87
|
+
case 6: {
|
|
88
|
+
if (tag !== 50) {
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
message.payloadRef = reader.string();
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
77
94
|
}
|
|
78
95
|
if ((tag & 7) === 4 || tag === 0) {
|
|
79
96
|
break;
|
|
@@ -97,6 +114,11 @@ exports.PublishStreamMessageRequest = {
|
|
|
97
114
|
: isSet(object.producer_seq)
|
|
98
115
|
? globalThis.Number(object.producer_seq)
|
|
99
116
|
: 0,
|
|
117
|
+
payloadRef: isSet(object.payloadRef)
|
|
118
|
+
? globalThis.String(object.payloadRef)
|
|
119
|
+
: isSet(object.payload_ref)
|
|
120
|
+
? globalThis.String(object.payload_ref)
|
|
121
|
+
: '',
|
|
100
122
|
};
|
|
101
123
|
},
|
|
102
124
|
toJSON(message) {
|
|
@@ -116,19 +138,23 @@ exports.PublishStreamMessageRequest = {
|
|
|
116
138
|
if (message.producerSeq !== 0) {
|
|
117
139
|
obj.producerSeq = Math.round(message.producerSeq);
|
|
118
140
|
}
|
|
141
|
+
if (message.payloadRef !== '') {
|
|
142
|
+
obj.payloadRef = message.payloadRef;
|
|
143
|
+
}
|
|
119
144
|
return obj;
|
|
120
145
|
},
|
|
121
146
|
create(base) {
|
|
122
147
|
return exports.PublishStreamMessageRequest.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
123
148
|
},
|
|
124
149
|
fromPartial(object) {
|
|
125
|
-
var _a, _b, _c, _d, _e;
|
|
150
|
+
var _a, _b, _c, _d, _e, _f;
|
|
126
151
|
const message = createBasePublishStreamMessageRequest();
|
|
127
152
|
message.namespace = (_a = object.namespace) !== null && _a !== void 0 ? _a : '';
|
|
128
153
|
message.topic = (_b = object.topic) !== null && _b !== void 0 ? _b : '';
|
|
129
154
|
message.payload = (_c = object.payload) !== null && _c !== void 0 ? _c : new Uint8Array(0);
|
|
130
155
|
message.producerId = (_d = object.producerId) !== null && _d !== void 0 ? _d : '';
|
|
131
156
|
message.producerSeq = (_e = object.producerSeq) !== null && _e !== void 0 ? _e : 0;
|
|
157
|
+
message.payloadRef = (_f = object.payloadRef) !== null && _f !== void 0 ? _f : '';
|
|
132
158
|
return message;
|
|
133
159
|
},
|
|
134
160
|
};
|
|
@@ -341,7 +367,7 @@ exports.StreamMessage = {
|
|
|
341
367
|
},
|
|
342
368
|
};
|
|
343
369
|
function createBaseStreamEntry() {
|
|
344
|
-
return { payload: new Uint8Array(0), cursor: '', createdAt: undefined };
|
|
370
|
+
return { payload: new Uint8Array(0), cursor: '', createdAt: undefined, payloadRef: '' };
|
|
345
371
|
}
|
|
346
372
|
exports.StreamEntry = {
|
|
347
373
|
encode(message, writer = new wire_1.BinaryWriter()) {
|
|
@@ -354,6 +380,9 @@ exports.StreamEntry = {
|
|
|
354
380
|
if (message.createdAt !== undefined) {
|
|
355
381
|
timestamp_1.Timestamp.encode(toTimestamp(message.createdAt), writer.uint32(26).fork()).join();
|
|
356
382
|
}
|
|
383
|
+
if (message.payloadRef !== '') {
|
|
384
|
+
writer.uint32(34).string(message.payloadRef);
|
|
385
|
+
}
|
|
357
386
|
return writer;
|
|
358
387
|
},
|
|
359
388
|
decode(input, length) {
|
|
@@ -384,6 +413,13 @@ exports.StreamEntry = {
|
|
|
384
413
|
message.createdAt = fromTimestamp(timestamp_1.Timestamp.decode(reader, reader.uint32()));
|
|
385
414
|
continue;
|
|
386
415
|
}
|
|
416
|
+
case 4: {
|
|
417
|
+
if (tag !== 34) {
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
message.payloadRef = reader.string();
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
387
423
|
}
|
|
388
424
|
if ((tag & 7) === 4 || tag === 0) {
|
|
389
425
|
break;
|
|
@@ -401,6 +437,11 @@ exports.StreamEntry = {
|
|
|
401
437
|
: isSet(object.created_at)
|
|
402
438
|
? fromJsonTimestamp(object.created_at)
|
|
403
439
|
: undefined,
|
|
440
|
+
payloadRef: isSet(object.payloadRef)
|
|
441
|
+
? globalThis.String(object.payloadRef)
|
|
442
|
+
: isSet(object.payload_ref)
|
|
443
|
+
? globalThis.String(object.payload_ref)
|
|
444
|
+
: '',
|
|
404
445
|
};
|
|
405
446
|
},
|
|
406
447
|
toJSON(message) {
|
|
@@ -414,17 +455,242 @@ exports.StreamEntry = {
|
|
|
414
455
|
if (message.createdAt !== undefined) {
|
|
415
456
|
obj.createdAt = message.createdAt.toISOString();
|
|
416
457
|
}
|
|
458
|
+
if (message.payloadRef !== '') {
|
|
459
|
+
obj.payloadRef = message.payloadRef;
|
|
460
|
+
}
|
|
417
461
|
return obj;
|
|
418
462
|
},
|
|
419
463
|
create(base) {
|
|
420
464
|
return exports.StreamEntry.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
421
465
|
},
|
|
422
466
|
fromPartial(object) {
|
|
423
|
-
var _a, _b, _c;
|
|
467
|
+
var _a, _b, _c, _d;
|
|
424
468
|
const message = createBaseStreamEntry();
|
|
425
469
|
message.payload = (_a = object.payload) !== null && _a !== void 0 ? _a : new Uint8Array(0);
|
|
426
470
|
message.cursor = (_b = object.cursor) !== null && _b !== void 0 ? _b : '';
|
|
427
471
|
message.createdAt = (_c = object.createdAt) !== null && _c !== void 0 ? _c : undefined;
|
|
472
|
+
message.payloadRef = (_d = object.payloadRef) !== null && _d !== void 0 ? _d : '';
|
|
473
|
+
return message;
|
|
474
|
+
},
|
|
475
|
+
};
|
|
476
|
+
function createBaseGetStreamTopicMetadataRequest() {
|
|
477
|
+
return { namespace: '', topic: '' };
|
|
478
|
+
}
|
|
479
|
+
exports.GetStreamTopicMetadataRequest = {
|
|
480
|
+
encode(message, writer = new wire_1.BinaryWriter()) {
|
|
481
|
+
if (message.namespace !== '') {
|
|
482
|
+
writer.uint32(10).string(message.namespace);
|
|
483
|
+
}
|
|
484
|
+
if (message.topic !== '') {
|
|
485
|
+
writer.uint32(18).string(message.topic);
|
|
486
|
+
}
|
|
487
|
+
return writer;
|
|
488
|
+
},
|
|
489
|
+
decode(input, length) {
|
|
490
|
+
const reader = input instanceof wire_1.BinaryReader ? input : new wire_1.BinaryReader(input);
|
|
491
|
+
const end = length === undefined ? reader.len : reader.pos + length;
|
|
492
|
+
const message = createBaseGetStreamTopicMetadataRequest();
|
|
493
|
+
while (reader.pos < end) {
|
|
494
|
+
const tag = reader.uint32();
|
|
495
|
+
switch (tag >>> 3) {
|
|
496
|
+
case 1: {
|
|
497
|
+
if (tag !== 10) {
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
message.namespace = reader.string();
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
case 2: {
|
|
504
|
+
if (tag !== 18) {
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
message.topic = reader.string();
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
reader.skip(tag & 7);
|
|
515
|
+
}
|
|
516
|
+
return message;
|
|
517
|
+
},
|
|
518
|
+
fromJSON(object) {
|
|
519
|
+
return {
|
|
520
|
+
namespace: isSet(object.namespace) ? globalThis.String(object.namespace) : '',
|
|
521
|
+
topic: isSet(object.topic) ? globalThis.String(object.topic) : '',
|
|
522
|
+
};
|
|
523
|
+
},
|
|
524
|
+
toJSON(message) {
|
|
525
|
+
const obj = {};
|
|
526
|
+
if (message.namespace !== '') {
|
|
527
|
+
obj.namespace = message.namespace;
|
|
528
|
+
}
|
|
529
|
+
if (message.topic !== '') {
|
|
530
|
+
obj.topic = message.topic;
|
|
531
|
+
}
|
|
532
|
+
return obj;
|
|
533
|
+
},
|
|
534
|
+
create(base) {
|
|
535
|
+
return exports.GetStreamTopicMetadataRequest.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
536
|
+
},
|
|
537
|
+
fromPartial(object) {
|
|
538
|
+
var _a, _b;
|
|
539
|
+
const message = createBaseGetStreamTopicMetadataRequest();
|
|
540
|
+
message.namespace = (_a = object.namespace) !== null && _a !== void 0 ? _a : '';
|
|
541
|
+
message.topic = (_b = object.topic) !== null && _b !== void 0 ? _b : '';
|
|
542
|
+
return message;
|
|
543
|
+
},
|
|
544
|
+
};
|
|
545
|
+
function createBaseStreamTopicMetadata() {
|
|
546
|
+
return {
|
|
547
|
+
namespace: '',
|
|
548
|
+
topic: '',
|
|
549
|
+
tenantId: '',
|
|
550
|
+
latestCursor: undefined,
|
|
551
|
+
messageCount: 0,
|
|
552
|
+
lastPublishedAt: undefined,
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
exports.StreamTopicMetadata = {
|
|
556
|
+
encode(message, writer = new wire_1.BinaryWriter()) {
|
|
557
|
+
if (message.namespace !== '') {
|
|
558
|
+
writer.uint32(10).string(message.namespace);
|
|
559
|
+
}
|
|
560
|
+
if (message.topic !== '') {
|
|
561
|
+
writer.uint32(18).string(message.topic);
|
|
562
|
+
}
|
|
563
|
+
if (message.tenantId !== '') {
|
|
564
|
+
writer.uint32(26).string(message.tenantId);
|
|
565
|
+
}
|
|
566
|
+
if (message.latestCursor !== undefined) {
|
|
567
|
+
writer.uint32(34).string(message.latestCursor);
|
|
568
|
+
}
|
|
569
|
+
if (message.messageCount !== 0) {
|
|
570
|
+
writer.uint32(40).int64(message.messageCount);
|
|
571
|
+
}
|
|
572
|
+
if (message.lastPublishedAt !== undefined) {
|
|
573
|
+
timestamp_1.Timestamp.encode(toTimestamp(message.lastPublishedAt), writer.uint32(50).fork()).join();
|
|
574
|
+
}
|
|
575
|
+
return writer;
|
|
576
|
+
},
|
|
577
|
+
decode(input, length) {
|
|
578
|
+
const reader = input instanceof wire_1.BinaryReader ? input : new wire_1.BinaryReader(input);
|
|
579
|
+
const end = length === undefined ? reader.len : reader.pos + length;
|
|
580
|
+
const message = createBaseStreamTopicMetadata();
|
|
581
|
+
while (reader.pos < end) {
|
|
582
|
+
const tag = reader.uint32();
|
|
583
|
+
switch (tag >>> 3) {
|
|
584
|
+
case 1: {
|
|
585
|
+
if (tag !== 10) {
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
588
|
+
message.namespace = reader.string();
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
case 2: {
|
|
592
|
+
if (tag !== 18) {
|
|
593
|
+
break;
|
|
594
|
+
}
|
|
595
|
+
message.topic = reader.string();
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
case 3: {
|
|
599
|
+
if (tag !== 26) {
|
|
600
|
+
break;
|
|
601
|
+
}
|
|
602
|
+
message.tenantId = reader.string();
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
case 4: {
|
|
606
|
+
if (tag !== 34) {
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
message.latestCursor = reader.string();
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
case 5: {
|
|
613
|
+
if (tag !== 40) {
|
|
614
|
+
break;
|
|
615
|
+
}
|
|
616
|
+
message.messageCount = longToNumber(reader.int64());
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
case 6: {
|
|
620
|
+
if (tag !== 50) {
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
message.lastPublishedAt = fromTimestamp(timestamp_1.Timestamp.decode(reader, reader.uint32()));
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
628
|
+
break;
|
|
629
|
+
}
|
|
630
|
+
reader.skip(tag & 7);
|
|
631
|
+
}
|
|
632
|
+
return message;
|
|
633
|
+
},
|
|
634
|
+
fromJSON(object) {
|
|
635
|
+
return {
|
|
636
|
+
namespace: isSet(object.namespace) ? globalThis.String(object.namespace) : '',
|
|
637
|
+
topic: isSet(object.topic) ? globalThis.String(object.topic) : '',
|
|
638
|
+
tenantId: isSet(object.tenantId)
|
|
639
|
+
? globalThis.String(object.tenantId)
|
|
640
|
+
: isSet(object.tenant_id)
|
|
641
|
+
? globalThis.String(object.tenant_id)
|
|
642
|
+
: '',
|
|
643
|
+
latestCursor: isSet(object.latestCursor)
|
|
644
|
+
? globalThis.String(object.latestCursor)
|
|
645
|
+
: isSet(object.latest_cursor)
|
|
646
|
+
? globalThis.String(object.latest_cursor)
|
|
647
|
+
: undefined,
|
|
648
|
+
messageCount: isSet(object.messageCount)
|
|
649
|
+
? globalThis.Number(object.messageCount)
|
|
650
|
+
: isSet(object.message_count)
|
|
651
|
+
? globalThis.Number(object.message_count)
|
|
652
|
+
: 0,
|
|
653
|
+
lastPublishedAt: isSet(object.lastPublishedAt)
|
|
654
|
+
? fromJsonTimestamp(object.lastPublishedAt)
|
|
655
|
+
: isSet(object.last_published_at)
|
|
656
|
+
? fromJsonTimestamp(object.last_published_at)
|
|
657
|
+
: undefined,
|
|
658
|
+
};
|
|
659
|
+
},
|
|
660
|
+
toJSON(message) {
|
|
661
|
+
const obj = {};
|
|
662
|
+
if (message.namespace !== '') {
|
|
663
|
+
obj.namespace = message.namespace;
|
|
664
|
+
}
|
|
665
|
+
if (message.topic !== '') {
|
|
666
|
+
obj.topic = message.topic;
|
|
667
|
+
}
|
|
668
|
+
if (message.tenantId !== '') {
|
|
669
|
+
obj.tenantId = message.tenantId;
|
|
670
|
+
}
|
|
671
|
+
if (message.latestCursor !== undefined) {
|
|
672
|
+
obj.latestCursor = message.latestCursor;
|
|
673
|
+
}
|
|
674
|
+
if (message.messageCount !== 0) {
|
|
675
|
+
obj.messageCount = Math.round(message.messageCount);
|
|
676
|
+
}
|
|
677
|
+
if (message.lastPublishedAt !== undefined) {
|
|
678
|
+
obj.lastPublishedAt = message.lastPublishedAt.toISOString();
|
|
679
|
+
}
|
|
680
|
+
return obj;
|
|
681
|
+
},
|
|
682
|
+
create(base) {
|
|
683
|
+
return exports.StreamTopicMetadata.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
684
|
+
},
|
|
685
|
+
fromPartial(object) {
|
|
686
|
+
var _a, _b, _c, _d, _e, _f;
|
|
687
|
+
const message = createBaseStreamTopicMetadata();
|
|
688
|
+
message.namespace = (_a = object.namespace) !== null && _a !== void 0 ? _a : '';
|
|
689
|
+
message.topic = (_b = object.topic) !== null && _b !== void 0 ? _b : '';
|
|
690
|
+
message.tenantId = (_c = object.tenantId) !== null && _c !== void 0 ? _c : '';
|
|
691
|
+
message.latestCursor = (_d = object.latestCursor) !== null && _d !== void 0 ? _d : undefined;
|
|
692
|
+
message.messageCount = (_e = object.messageCount) !== null && _e !== void 0 ? _e : 0;
|
|
693
|
+
message.lastPublishedAt = (_f = object.lastPublishedAt) !== null && _f !== void 0 ? _f : undefined;
|
|
428
694
|
return message;
|
|
429
695
|
},
|
|
430
696
|
};
|
|
@@ -448,6 +714,14 @@ exports.V1StreamsDefinition = {
|
|
|
448
714
|
responseStream: true,
|
|
449
715
|
options: {},
|
|
450
716
|
},
|
|
717
|
+
getTopicMetadata: {
|
|
718
|
+
name: 'GetTopicMetadata',
|
|
719
|
+
requestType: exports.GetStreamTopicMetadataRequest,
|
|
720
|
+
requestStream: false,
|
|
721
|
+
responseType: exports.StreamTopicMetadata,
|
|
722
|
+
responseStream: false,
|
|
723
|
+
options: {},
|
|
724
|
+
},
|
|
451
725
|
},
|
|
452
726
|
};
|
|
453
727
|
function bytesFromBase64(b64) {
|
|
@@ -29,6 +29,13 @@ export type PublishStreamMessageRequest = Message<"v1.PublishStreamMessageReques
|
|
|
29
29
|
* @generated from field: int64 producer_seq = 5;
|
|
30
30
|
*/
|
|
31
31
|
producerSeq: bigint;
|
|
32
|
+
/**
|
|
33
|
+
* instead of payload: a ref returned by the stream payload upload endpoint,
|
|
34
|
+
* for payloads too large for one gRPC message
|
|
35
|
+
*
|
|
36
|
+
* @generated from field: string payload_ref = 6;
|
|
37
|
+
*/
|
|
38
|
+
payloadRef: string;
|
|
32
39
|
};
|
|
33
40
|
/**
|
|
34
41
|
* Describes the message v1.PublishStreamMessageRequest.
|
|
@@ -104,12 +111,76 @@ export type StreamEntry = Message<"v1.StreamEntry"> & {
|
|
|
104
111
|
* @generated from field: google.protobuf.Timestamp created_at = 3;
|
|
105
112
|
*/
|
|
106
113
|
createdAt?: Timestamp | undefined;
|
|
114
|
+
/**
|
|
115
|
+
* instead of payload: fetch it from the stream payload endpoint by this ref
|
|
116
|
+
*
|
|
117
|
+
* @generated from field: string payload_ref = 4;
|
|
118
|
+
*/
|
|
119
|
+
payloadRef: string;
|
|
107
120
|
};
|
|
108
121
|
/**
|
|
109
122
|
* Describes the message v1.StreamEntry.
|
|
110
123
|
* Use `create(StreamEntrySchema)` to create a new message.
|
|
111
124
|
*/
|
|
112
125
|
export declare const StreamEntrySchema: GenMessage<StreamEntry>;
|
|
126
|
+
/**
|
|
127
|
+
* @generated from message v1.GetStreamTopicMetadataRequest
|
|
128
|
+
*/
|
|
129
|
+
export type GetStreamTopicMetadataRequest = Message<"v1.GetStreamTopicMetadataRequest"> & {
|
|
130
|
+
/**
|
|
131
|
+
* @generated from field: string namespace = 1;
|
|
132
|
+
*/
|
|
133
|
+
namespace: string;
|
|
134
|
+
/**
|
|
135
|
+
* @generated from field: string topic = 2;
|
|
136
|
+
*/
|
|
137
|
+
topic: string;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Describes the message v1.GetStreamTopicMetadataRequest.
|
|
141
|
+
* Use `create(GetStreamTopicMetadataRequestSchema)` to create a new message.
|
|
142
|
+
*/
|
|
143
|
+
export declare const GetStreamTopicMetadataRequestSchema: GenMessage<GetStreamTopicMetadataRequest>;
|
|
144
|
+
/**
|
|
145
|
+
* Counts and the latest message cover only what's within the tenant's retention.
|
|
146
|
+
*
|
|
147
|
+
* @generated from message v1.StreamTopicMetadata
|
|
148
|
+
*/
|
|
149
|
+
export type StreamTopicMetadata = Message<"v1.StreamTopicMetadata"> & {
|
|
150
|
+
/**
|
|
151
|
+
* @generated from field: string namespace = 1;
|
|
152
|
+
*/
|
|
153
|
+
namespace: string;
|
|
154
|
+
/**
|
|
155
|
+
* @generated from field: string topic = 2;
|
|
156
|
+
*/
|
|
157
|
+
topic: string;
|
|
158
|
+
/**
|
|
159
|
+
* @generated from field: string tenant_id = 3;
|
|
160
|
+
*/
|
|
161
|
+
tenantId: string;
|
|
162
|
+
/**
|
|
163
|
+
* resumes a subscription after the newest retained message; unset when none is retained
|
|
164
|
+
*
|
|
165
|
+
* @generated from field: optional string latest_cursor = 4;
|
|
166
|
+
*/
|
|
167
|
+
latestCursor?: string | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* @generated from field: int64 message_count = 5;
|
|
170
|
+
*/
|
|
171
|
+
messageCount: bigint;
|
|
172
|
+
/**
|
|
173
|
+
* when the newest retained message was stored; unset when none is retained
|
|
174
|
+
*
|
|
175
|
+
* @generated from field: google.protobuf.Timestamp last_published_at = 6;
|
|
176
|
+
*/
|
|
177
|
+
lastPublishedAt?: Timestamp | undefined;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Describes the message v1.StreamTopicMetadata.
|
|
181
|
+
* Use `create(StreamTopicMetadataSchema)` to create a new message.
|
|
182
|
+
*/
|
|
183
|
+
export declare const StreamTopicMetadataSchema: GenMessage<StreamTopicMetadata>;
|
|
113
184
|
/**
|
|
114
185
|
* @generated from service v1.V1Streams
|
|
115
186
|
*/
|
|
@@ -130,4 +201,12 @@ export declare const V1Streams: GenService<{
|
|
|
130
201
|
input: typeof SubscribeStreamRequestSchema;
|
|
131
202
|
output: typeof StreamMessageSchema;
|
|
132
203
|
};
|
|
204
|
+
/**
|
|
205
|
+
* @generated from rpc v1.V1Streams.GetTopicMetadata
|
|
206
|
+
*/
|
|
207
|
+
getTopicMetadata: {
|
|
208
|
+
methodKind: "unary";
|
|
209
|
+
input: typeof GetStreamTopicMetadataRequestSchema;
|
|
210
|
+
output: typeof StreamTopicMetadataSchema;
|
|
211
|
+
};
|
|
133
212
|
}>;
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
// @generated from file v1/streams.proto (package v1, syntax proto3)
|
|
4
4
|
/* eslint-disable */
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.V1Streams = exports.StreamEntrySchema = exports.StreamMessageSchema = exports.SubscribeStreamRequestSchema = exports.PublishStreamMessageResponseSchema = exports.PublishStreamMessageRequestSchema = exports.file_v1_streams = void 0;
|
|
6
|
+
exports.V1Streams = exports.StreamTopicMetadataSchema = exports.GetStreamTopicMetadataRequestSchema = exports.StreamEntrySchema = exports.StreamMessageSchema = exports.SubscribeStreamRequestSchema = exports.PublishStreamMessageResponseSchema = exports.PublishStreamMessageRequestSchema = exports.file_v1_streams = void 0;
|
|
7
7
|
const codegenv2_1 = require("@bufbuild/protobuf/codegenv2");
|
|
8
8
|
const wkt_1 = require("@bufbuild/protobuf/wkt");
|
|
9
9
|
/**
|
|
10
10
|
* Describes the file v1/streams.proto.
|
|
11
11
|
*/
|
|
12
|
-
exports.file_v1_streams = (0, codegenv2_1.fileDesc)("
|
|
12
|
+
exports.file_v1_streams = (0, codegenv2_1.fileDesc)("ChB2MS9zdHJlYW1zLnByb3RvEgJ2MSKQAQobUHVibGlzaFN0cmVhbU1lc3NhZ2VSZXF1ZXN0EhEKCW5hbWVzcGFjZRgBIAEoCRINCgV0b3BpYxgCIAEoCRIPCgdwYXlsb2FkGAMgASgMEhMKC3Byb2R1Y2VyX2lkGAQgASgJEhQKDHByb2R1Y2VyX3NlcRgFIAEoAxITCgtwYXlsb2FkX3JlZhgGIAEoCSIeChxQdWJsaXNoU3RyZWFtTWVzc2FnZVJlc3BvbnNlIloKFlN1YnNjcmliZVN0cmVhbVJlcXVlc3QSEQoJbmFtZXNwYWNlGAEgASgJEg0KBXRvcGljGAIgASgJEhMKBmN1cnNvchgDIAEoCUgAiAEBQgkKB19jdXJzb3IiUQoNU3RyZWFtTWVzc2FnZRIgCgdlbnRyaWVzGAEgAygLMg8udjEuU3RyZWFtRW50cnkSDgoGaGFuZ3VwGAIgASgIEg4KBmN1cnNvchgDIAEoCSJzCgtTdHJlYW1FbnRyeRIPCgdwYXlsb2FkGAEgASgMEg4KBmN1cnNvchgCIAEoCRIuCgpjcmVhdGVkX2F0GAMgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBITCgtwYXlsb2FkX3JlZhgEIAEoCSJBCh1HZXRTdHJlYW1Ub3BpY01ldGFkYXRhUmVxdWVzdBIRCgluYW1lc3BhY2UYASABKAkSDQoFdG9waWMYAiABKAkixgEKE1N0cmVhbVRvcGljTWV0YWRhdGESEQoJbmFtZXNwYWNlGAEgASgJEg0KBXRvcGljGAIgASgJEhEKCXRlbmFudF9pZBgDIAEoCRIaCg1sYXRlc3RfY3Vyc29yGAQgASgJSACIAQESFQoNbWVzc2FnZV9jb3VudBgFIAEoAxI1ChFsYXN0X3B1Ymxpc2hlZF9hdBgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCEAoOX2xhdGVzdF9jdXJzb3Iy7QEKCVYxU3RyZWFtcxJOCgdQdWJsaXNoEh8udjEuUHVibGlzaFN0cmVhbU1lc3NhZ2VSZXF1ZXN0GiAudjEuUHVibGlzaFN0cmVhbU1lc3NhZ2VSZXNwb25zZSIAEj4KCVN1YnNjcmliZRIaLnYxLlN1YnNjcmliZVN0cmVhbVJlcXVlc3QaES52MS5TdHJlYW1NZXNzYWdlIgAwARJQChBHZXRUb3BpY01ldGFkYXRhEiEudjEuR2V0U3RyZWFtVG9waWNNZXRhZGF0YVJlcXVlc3QaFy52MS5TdHJlYW1Ub3BpY01ldGFkYXRhIgBCQlpAZ2l0aHViLmNvbS9oYXRjaGV0LWRldi9oYXRjaGV0L2ludGVybmFsL3NlcnZpY2VzL3NoYXJlZC9wcm90by92MWIGcHJvdG8z", [wkt_1.file_google_protobuf_timestamp]);
|
|
13
13
|
/**
|
|
14
14
|
* Describes the message v1.PublishStreamMessageRequest.
|
|
15
15
|
* Use `create(PublishStreamMessageRequestSchema)` to create a new message.
|
|
@@ -35,6 +35,16 @@ exports.StreamMessageSchema = (0, codegenv2_1.messageDesc)(exports.file_v1_strea
|
|
|
35
35
|
* Use `create(StreamEntrySchema)` to create a new message.
|
|
36
36
|
*/
|
|
37
37
|
exports.StreamEntrySchema = (0, codegenv2_1.messageDesc)(exports.file_v1_streams, 4);
|
|
38
|
+
/**
|
|
39
|
+
* Describes the message v1.GetStreamTopicMetadataRequest.
|
|
40
|
+
* Use `create(GetStreamTopicMetadataRequestSchema)` to create a new message.
|
|
41
|
+
*/
|
|
42
|
+
exports.GetStreamTopicMetadataRequestSchema = (0, codegenv2_1.messageDesc)(exports.file_v1_streams, 5);
|
|
43
|
+
/**
|
|
44
|
+
* Describes the message v1.StreamTopicMetadata.
|
|
45
|
+
* Use `create(StreamTopicMetadataSchema)` to create a new message.
|
|
46
|
+
*/
|
|
47
|
+
exports.StreamTopicMetadataSchema = (0, codegenv2_1.messageDesc)(exports.file_v1_streams, 6);
|
|
38
48
|
/**
|
|
39
49
|
* @generated from service v1.V1Streams
|
|
40
50
|
*/
|
|
@@ -7,6 +7,17 @@ export type StreamEvent = {
|
|
|
7
7
|
/** when the message was stored */
|
|
8
8
|
createdAt?: Date;
|
|
9
9
|
};
|
|
10
|
+
/** Covers only messages within the tenant's retention. */
|
|
11
|
+
export type StreamTopicMetadata = {
|
|
12
|
+
namespace: string;
|
|
13
|
+
topic: string;
|
|
14
|
+
tenantId: string;
|
|
15
|
+
messageCount: number;
|
|
16
|
+
/** resumes events() after the newest retained message; undefined when none is retained */
|
|
17
|
+
latestCursor?: string;
|
|
18
|
+
/** when the newest retained message was stored; undefined when none is retained */
|
|
19
|
+
lastPublishedAt?: Date;
|
|
20
|
+
};
|
|
10
21
|
export type StreamCallOptions = {
|
|
11
22
|
namespace?: string;
|
|
12
23
|
cursor?: string;
|
|
@@ -20,11 +31,15 @@ export type StreamCallOptions = {
|
|
|
20
31
|
*/
|
|
21
32
|
export declare class StreamsClient {
|
|
22
33
|
private _config;
|
|
34
|
+
private _client;
|
|
23
35
|
private _grpc;
|
|
24
36
|
private producers;
|
|
25
37
|
private publishChains;
|
|
26
38
|
constructor(client: HatchetClient);
|
|
27
39
|
private get grpc();
|
|
40
|
+
private static withRetries;
|
|
41
|
+
private uploadPayload;
|
|
42
|
+
private fetchPayload;
|
|
28
43
|
private publishOrdered;
|
|
29
44
|
/**
|
|
30
45
|
* Resolves once the message is stored. A client's messages to a topic are
|
|
@@ -34,6 +49,13 @@ export declare class StreamsClient {
|
|
|
34
49
|
* @param options - optional namespace override
|
|
35
50
|
*/
|
|
36
51
|
publish(topic: string, message: Uint8Array | string, options?: StreamCallOptions): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Describes topic's retained messages. Rejects with a NOT_FOUND gRPC error
|
|
54
|
+
* for a topic nothing was published to.
|
|
55
|
+
* @param topic - the topic to describe
|
|
56
|
+
* @param options - optional namespace override
|
|
57
|
+
*/
|
|
58
|
+
topicMetadata(topic: string, options?: Pick<StreamCallOptions, 'namespace'>): Promise<StreamTopicMetadata>;
|
|
37
59
|
/**
|
|
38
60
|
* Yields topic's messages after options.cursor, or from the oldest retained.
|
|
39
61
|
* If the connection drops, it resubscribes from the last message yielded, so
|
|
@@ -34,6 +34,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
35
|
exports.StreamsClient = void 0;
|
|
36
36
|
const crypto_1 = require("crypto");
|
|
37
|
+
const axios_1 = require("axios");
|
|
37
38
|
const nice_grpc_1 = require("nice-grpc");
|
|
38
39
|
const grpc_helpers_1 = require("../../../util/grpc-helpers");
|
|
39
40
|
const grpc_error_1 = require("../../../util/grpc-error");
|
|
@@ -58,7 +59,27 @@ const permanentSubscribeErrors = new Set([
|
|
|
58
59
|
]);
|
|
59
60
|
const resubscribeMinDelayMs = 250;
|
|
60
61
|
const resubscribeMaxDelayMs = 10000;
|
|
62
|
+
// the server's limit for a payload sent over gRPC (MaxStreamMessagePayloadBytes)
|
|
63
|
+
const maxInlinePayloadBytes = 4 * 1024 * 1024 - 5 * 1024;
|
|
64
|
+
// the server's limit for an uploaded payload (MaxStreamUploadedPayloadBytes)
|
|
65
|
+
const maxUploadedPayloadBytes = 64 * 1024 * 1024;
|
|
66
|
+
const payloadRequestAttempts = 3;
|
|
67
|
+
function httpStatus(err) {
|
|
68
|
+
var _a;
|
|
69
|
+
return (0, axios_1.isAxiosError)(err) ? (_a = err.response) === null || _a === void 0 ? void 0 : _a.status : undefined;
|
|
70
|
+
}
|
|
71
|
+
// a payload fetch that got no response, a 5xx or a 429 may succeed later
|
|
72
|
+
function isTemporaryHttpError(err) {
|
|
73
|
+
if (!(0, axios_1.isAxiosError)(err)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const status = httpStatus(err);
|
|
77
|
+
return status === undefined || status >= 500 || status === 429;
|
|
78
|
+
}
|
|
61
79
|
function shouldResubscribe(err, attempt) {
|
|
80
|
+
if (isTemporaryHttpError(err)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
62
83
|
const code = (0, grpc_error_1.getGrpcErrorCode)(err);
|
|
63
84
|
if (code === undefined || permanentSubscribeErrors.has(code)) {
|
|
64
85
|
return false;
|
|
@@ -82,6 +103,7 @@ class StreamsClient {
|
|
|
82
103
|
// stored promise always resolves, so one failure doesn't block later calls
|
|
83
104
|
this.publishChains = new Map();
|
|
84
105
|
this._config = client.config;
|
|
106
|
+
this._client = client;
|
|
85
107
|
}
|
|
86
108
|
get grpc() {
|
|
87
109
|
if (!this._grpc) {
|
|
@@ -90,21 +112,46 @@ class StreamsClient {
|
|
|
90
112
|
}
|
|
91
113
|
return this._grpc;
|
|
92
114
|
}
|
|
93
|
-
|
|
94
|
-
|
|
115
|
+
// retries a 5xx or network failure; a 4xx won't succeed on retry
|
|
116
|
+
static withRetries(request) {
|
|
117
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
+
for (let attempt = 1;; attempt += 1) {
|
|
119
|
+
try {
|
|
120
|
+
return yield request();
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
const status = httpStatus(err);
|
|
124
|
+
if ((status !== undefined && status < 500) || attempt >= payloadRequestAttempts) {
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
uploadPayload(payload) {
|
|
132
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
133
|
+
const res = yield StreamsClient.withRetries(() => this._client.api.v1StreamPayloadUpload(this._config.tenant_id, {
|
|
134
|
+
payload: new Blob([payload]),
|
|
135
|
+
}));
|
|
136
|
+
return res.data.ref;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
fetchPayload(payloadRef, signal) {
|
|
140
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
141
|
+
const res = yield StreamsClient.withRetries(() => this._client.api.v1StreamPayloadGet(this._config.tenant_id, { ref: payloadRef }, { format: 'arraybuffer', signal }));
|
|
142
|
+
return new Uint8Array(res.data);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
publishOrdered(key_1, namespace_1, topic_1, body_1) {
|
|
146
|
+
return __awaiter(this, arguments, void 0, function* (key, namespace, topic, body, retryGap = true) {
|
|
95
147
|
let producer = this.producers.get(key);
|
|
96
148
|
if (!producer) {
|
|
97
149
|
producer = { producerId: (0, crypto_1.randomUUID)(), seq: 0 };
|
|
98
150
|
this.producers.set(key, producer);
|
|
99
151
|
}
|
|
100
152
|
try {
|
|
101
|
-
yield this.grpc.publish({
|
|
102
|
-
|
|
103
|
-
topic,
|
|
104
|
-
payload,
|
|
105
|
-
producerId: producer.producerId,
|
|
106
|
-
producerSeq: producer.seq,
|
|
107
|
-
});
|
|
153
|
+
yield this.grpc.publish(Object.assign(Object.assign({ namespace,
|
|
154
|
+
topic }, body), { producerId: producer.producerId, producerSeq: producer.seq }));
|
|
108
155
|
}
|
|
109
156
|
catch (err) {
|
|
110
157
|
// it may still land, and a different payload under its seq would be dropped as a duplicate
|
|
@@ -113,7 +160,7 @@ class StreamsClient {
|
|
|
113
160
|
}
|
|
114
161
|
// a gap stored nothing (e.g. the watermark passed cursor retention), so resend as the new producer
|
|
115
162
|
if (retryGap && (0, grpc_error_1.getGrpcErrorCode)(err) === nice_grpc_1.Status.FAILED_PRECONDITION) {
|
|
116
|
-
return this.publishOrdered(key, namespace, topic,
|
|
163
|
+
return this.publishOrdered(key, namespace, topic, body, false);
|
|
117
164
|
}
|
|
118
165
|
throw err;
|
|
119
166
|
}
|
|
@@ -133,12 +180,41 @@ class StreamsClient {
|
|
|
133
180
|
const payload = typeof message === 'string' ? new TextEncoder().encode(message) : message;
|
|
134
181
|
const namespace = (_a = options === null || options === void 0 ? void 0 : options.namespace) !== null && _a !== void 0 ? _a : '';
|
|
135
182
|
const key = `${namespace}\u0000${topic}`;
|
|
183
|
+
if (payload.byteLength > maxUploadedPayloadBytes) {
|
|
184
|
+
throw new Error(`payload exceeds maximum size of ${maxUploadedPayloadBytes} bytes`);
|
|
185
|
+
}
|
|
186
|
+
// uploaded before taking its place in the topic's order, so uploads overlap
|
|
187
|
+
const uploaded = payload.byteLength > maxInlinePayloadBytes ? this.uploadPayload(payload) : undefined;
|
|
188
|
+
// awaited in order below; this only keeps an early failure from reporting as unhandled
|
|
189
|
+
uploaded === null || uploaded === void 0 ? void 0 : uploaded.catch(() => { });
|
|
136
190
|
const previous = (_b = this.publishChains.get(key)) !== null && _b !== void 0 ? _b : Promise.resolve();
|
|
137
|
-
const publishPromise = previous.then(() => this
|
|
191
|
+
const publishPromise = previous.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
192
|
+
return this.publishOrdered(key, namespace, topic, uploaded ? { payloadRef: yield uploaded } : { payload });
|
|
193
|
+
}));
|
|
138
194
|
this.publishChains.set(key, publishPromise.catch(() => { }));
|
|
139
195
|
return publishPromise;
|
|
140
196
|
});
|
|
141
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Describes topic's retained messages. Rejects with a NOT_FOUND gRPC error
|
|
200
|
+
* for a topic nothing was published to.
|
|
201
|
+
* @param topic - the topic to describe
|
|
202
|
+
* @param options - optional namespace override
|
|
203
|
+
*/
|
|
204
|
+
topicMetadata(topic, options) {
|
|
205
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
206
|
+
var _a;
|
|
207
|
+
const res = yield this.grpc.getTopicMetadata({ namespace: (_a = options === null || options === void 0 ? void 0 : options.namespace) !== null && _a !== void 0 ? _a : '', topic });
|
|
208
|
+
return {
|
|
209
|
+
namespace: res.namespace,
|
|
210
|
+
topic: res.topic,
|
|
211
|
+
tenantId: res.tenantId,
|
|
212
|
+
messageCount: res.messageCount,
|
|
213
|
+
latestCursor: res.latestCursor,
|
|
214
|
+
lastPublishedAt: res.lastPublishedAt,
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
}
|
|
142
218
|
/**
|
|
143
219
|
* Yields topic's messages after options.cursor, or from the oldest retained.
|
|
144
220
|
* If the connection drops, it resubscribes from the last message yielded, so
|
|
@@ -167,11 +243,15 @@ class StreamsClient {
|
|
|
167
243
|
if (msg.hangup) {
|
|
168
244
|
return yield __await(void 0);
|
|
169
245
|
}
|
|
170
|
-
failures = 0;
|
|
171
246
|
for (const entry of msg.entries) {
|
|
247
|
+
const payload = entry.payloadRef
|
|
248
|
+
? yield __await(this.fetchPayload(entry.payloadRef, signal))
|
|
249
|
+
: entry.payload;
|
|
172
250
|
({ cursor } = entry);
|
|
251
|
+
// reset only on delivery, so a payload fetch failing on every reconnect still backs off
|
|
252
|
+
failures = 0;
|
|
173
253
|
yield yield __await({
|
|
174
|
-
payload
|
|
254
|
+
payload,
|
|
175
255
|
cursor: entry.cursor,
|
|
176
256
|
createdAt: entry.createdAt,
|
|
177
257
|
});
|
|
@@ -639,7 +639,7 @@ class InternalWorker {
|
|
|
639
639
|
}
|
|
640
640
|
shutdown() {
|
|
641
641
|
return __awaiter(this, void 0, void 0, function* () {
|
|
642
|
-
var _a
|
|
642
|
+
var _a;
|
|
643
643
|
this.killing = true;
|
|
644
644
|
this.setStatus(health_server_1.workerStatus.UNHEALTHY);
|
|
645
645
|
this.logger.info('Starting to exit...');
|
|
@@ -670,15 +670,17 @@ class InternalWorker {
|
|
|
670
670
|
catch (e) {
|
|
671
671
|
this.logger.error(`Could not stop durable listener: ${e.message}`);
|
|
672
672
|
}
|
|
673
|
-
(_a = this.listener) === null || _a === void 0 ? void 0 : _a.stopStream();
|
|
674
673
|
this.logger.info('Gracefully exiting hatchet worker, running tasks will attempt to finish...');
|
|
675
|
-
//
|
|
676
|
-
|
|
674
|
+
// Awaits the underlying work rather than the cancelable wrapper, which rejects as soon as a
|
|
675
|
+
// cancellation arrives while the task is still winding down.
|
|
676
|
+
yield Promise.allSettled(Object.values(this.futures).map(({ inner }) => inner));
|
|
677
677
|
this.logger.info('Successfully finished pending tasks.');
|
|
678
|
-
// Unregistering stops the heartbeat, so it has to wait until
|
|
679
|
-
//
|
|
678
|
+
// Unregistering closes the action stream and stops the heartbeat, so it has to wait until
|
|
679
|
+
// the running tasks are done. Stopping the heartbeat earlier lets the engine treat the worker
|
|
680
|
+
// as dead and reassign tasks that are about to complete, and closing the stream earlier makes
|
|
681
|
+
// the engine reject every heartbeat sent while those tasks finish.
|
|
680
682
|
try {
|
|
681
|
-
yield ((
|
|
683
|
+
yield ((_a = this.listener) === null || _a === void 0 ? void 0 : _a.unregister());
|
|
682
684
|
}
|
|
683
685
|
catch (e) {
|
|
684
686
|
this.logger.error(`Could not unregister listener: ${e.message}`);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { HatchetClient } from '../..';
|
|
2
|
+
import { StreamEvent } from '../../client/features/streams';
|
|
3
|
+
export declare const MiB: number;
|
|
4
|
+
export declare const maxInlinePayloadBytes: number;
|
|
5
|
+
export declare const describeBenchmark: jest.Describe;
|
|
6
|
+
export type LatencyStats = {
|
|
7
|
+
count: number;
|
|
8
|
+
avgMs: number;
|
|
9
|
+
p50Ms: number;
|
|
10
|
+
p99Ms: number;
|
|
11
|
+
maxMs: number;
|
|
12
|
+
};
|
|
13
|
+
export declare function latencyStats(durationsMs: number[]): LatencyStats;
|
|
14
|
+
export declare function formatLatency(stats: LatencyStats, digits?: number): string;
|
|
15
|
+
export declare function formatSize(bytes: number): string;
|
|
16
|
+
export type PublishLatencyStats = LatencyStats & {
|
|
17
|
+
throughputPerSec: number;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Times `count` sequential publishes, after `warmupCount` unmeasured ones
|
|
21
|
+
* absorb connection setup and topic creation.
|
|
22
|
+
*/
|
|
23
|
+
export declare function measurePublishLatency(hatchet: HatchetClient, topic: string, payload: Uint8Array | string, count: number, warmupCount?: number): Promise<PublishLatencyStats>;
|
|
24
|
+
export declare function formatPublishLatency(stats: PublishLatencyStats): string;
|
|
25
|
+
export type LiveSubscription = {
|
|
26
|
+
/** resolves with the next message delivered after the call */
|
|
27
|
+
nextEvent: () => Promise<StreamEvent>;
|
|
28
|
+
close: () => Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Subscribes to topic and resolves once the subscription is live, so a
|
|
32
|
+
* benchmark's timings don't include subscribe setup.
|
|
33
|
+
*/
|
|
34
|
+
export declare function openLiveSubscription(hatchet: HatchetClient, topic: string): Promise<LiveSubscription>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
12
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
13
|
+
var m = o[Symbol.asyncIterator], i;
|
|
14
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
15
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
16
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.describeBenchmark = exports.maxInlinePayloadBytes = exports.MiB = void 0;
|
|
20
|
+
exports.latencyStats = latencyStats;
|
|
21
|
+
exports.formatLatency = formatLatency;
|
|
22
|
+
exports.formatSize = formatSize;
|
|
23
|
+
exports.measurePublishLatency = measurePublishLatency;
|
|
24
|
+
exports.formatPublishLatency = formatPublishLatency;
|
|
25
|
+
exports.openLiveSubscription = openLiveSubscription;
|
|
26
|
+
const perf_hooks_1 = require("perf_hooks");
|
|
27
|
+
exports.MiB = 1024 * 1024;
|
|
28
|
+
// the server's per-message gRPC limit (MaxStreamMessagePayloadBytes); larger payloads are uploaded
|
|
29
|
+
exports.maxInlinePayloadBytes = 4 * exports.MiB - 5 * 1024;
|
|
30
|
+
// benchmarks run only when asked for (test_durable_streams.sh --bench)
|
|
31
|
+
exports.describeBenchmark = process.env.HATCHET_E2E_BENCHMARKS ? describe : describe.skip;
|
|
32
|
+
function percentile(sorted, p) {
|
|
33
|
+
return sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * p))];
|
|
34
|
+
}
|
|
35
|
+
function latencyStats(durationsMs) {
|
|
36
|
+
const sorted = [...durationsMs].sort((a, b) => a - b);
|
|
37
|
+
return {
|
|
38
|
+
count: durationsMs.length,
|
|
39
|
+
avgMs: durationsMs.reduce((sum, d) => sum + d, 0) / durationsMs.length,
|
|
40
|
+
p50Ms: percentile(sorted, 0.5),
|
|
41
|
+
p99Ms: percentile(sorted, 0.99),
|
|
42
|
+
maxMs: sorted[sorted.length - 1],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function formatLatency(stats, digits = 2) {
|
|
46
|
+
const fmt = (ms) => ms.toFixed(digits);
|
|
47
|
+
return `avg=${fmt(stats.avgMs)}ms p50=${fmt(stats.p50Ms)}ms p99=${fmt(stats.p99Ms)}ms max=${fmt(stats.maxMs)}ms`;
|
|
48
|
+
}
|
|
49
|
+
function formatSize(bytes) {
|
|
50
|
+
if (bytes % exports.MiB === 0)
|
|
51
|
+
return `${bytes / exports.MiB}MiB`;
|
|
52
|
+
if (bytes % 1024 === 0)
|
|
53
|
+
return `${bytes / 1024}KiB`;
|
|
54
|
+
return `${bytes}B`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Times `count` sequential publishes, after `warmupCount` unmeasured ones
|
|
58
|
+
* absorb connection setup and topic creation.
|
|
59
|
+
*/
|
|
60
|
+
function measurePublishLatency(hatchet_1, topic_1, payload_1, count_1) {
|
|
61
|
+
return __awaiter(this, arguments, void 0, function* (hatchet, topic, payload, count, warmupCount = 5) {
|
|
62
|
+
for (let i = 0; i < warmupCount; i += 1) {
|
|
63
|
+
yield hatchet.streams.publish(topic, payload);
|
|
64
|
+
}
|
|
65
|
+
const durationsMs = [];
|
|
66
|
+
const start = perf_hooks_1.performance.now();
|
|
67
|
+
for (let i = 0; i < count; i += 1) {
|
|
68
|
+
const before = perf_hooks_1.performance.now();
|
|
69
|
+
yield hatchet.streams.publish(topic, payload);
|
|
70
|
+
durationsMs.push(perf_hooks_1.performance.now() - before);
|
|
71
|
+
}
|
|
72
|
+
const totalMs = perf_hooks_1.performance.now() - start;
|
|
73
|
+
return Object.assign(Object.assign({}, latencyStats(durationsMs)), { throughputPerSec: (count / totalMs) * 1000 });
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function formatPublishLatency(stats) {
|
|
77
|
+
return `${formatLatency(stats)} throughput=${stats.throughputPerSec.toFixed(2)}/s`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Subscribes to topic and resolves once the subscription is live, so a
|
|
81
|
+
* benchmark's timings don't include subscribe setup.
|
|
82
|
+
*/
|
|
83
|
+
function openLiveSubscription(hatchet, topic) {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
const abort = new AbortController();
|
|
86
|
+
let onEvent;
|
|
87
|
+
const consumer = (() => __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
var _a, e_1, _b, _c;
|
|
89
|
+
try {
|
|
90
|
+
for (var _d = true, _e = __asyncValues(hatchet.streams.events(topic, { signal: abort.signal })), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
91
|
+
_c = _f.value;
|
|
92
|
+
_d = false;
|
|
93
|
+
const ev = _c;
|
|
94
|
+
onEvent === null || onEvent === void 0 ? void 0 : onEvent(ev);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
98
|
+
finally {
|
|
99
|
+
try {
|
|
100
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
101
|
+
}
|
|
102
|
+
finally { if (e_1) throw e_1.error; }
|
|
103
|
+
}
|
|
104
|
+
}))();
|
|
105
|
+
const nextEvent = () => new Promise((resolve) => {
|
|
106
|
+
onEvent = resolve;
|
|
107
|
+
});
|
|
108
|
+
// the subscription is live once a first message comes through
|
|
109
|
+
const ready = nextEvent();
|
|
110
|
+
yield hatchet.streams.publish(topic, 'ready');
|
|
111
|
+
yield ready;
|
|
112
|
+
return {
|
|
113
|
+
nextEvent,
|
|
114
|
+
close: () => __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
abort.abort();
|
|
116
|
+
yield consumer;
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
}
|
package/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const HATCHET_VERSION = "1.
|
|
1
|
+
export declare const HATCHET_VERSION = "1.36.0";
|
package/version.js
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { HatchetClient } from '../..';
|
|
2
|
-
export type PublishLatencyStats = {
|
|
3
|
-
count: number;
|
|
4
|
-
avgMs: number;
|
|
5
|
-
p50Ms: number;
|
|
6
|
-
p99Ms: number;
|
|
7
|
-
maxMs: number;
|
|
8
|
-
throughputPerSec: number;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Times `count` sequential publishes, after `warmupCount` unmeasured ones
|
|
12
|
-
* absorb connection setup and topic creation.
|
|
13
|
-
*/
|
|
14
|
-
export declare function measurePublishLatency(hatchet: HatchetClient, topic: string, payload: Uint8Array | string, count: number, warmupCount?: number): Promise<PublishLatencyStats>;
|
|
15
|
-
export declare function formatPublishLatency(stats: PublishLatencyStats): string;
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.measurePublishLatency = measurePublishLatency;
|
|
13
|
-
exports.formatPublishLatency = formatPublishLatency;
|
|
14
|
-
const perf_hooks_1 = require("perf_hooks");
|
|
15
|
-
function percentile(sorted, p) {
|
|
16
|
-
return sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * p))];
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Times `count` sequential publishes, after `warmupCount` unmeasured ones
|
|
20
|
-
* absorb connection setup and topic creation.
|
|
21
|
-
*/
|
|
22
|
-
function measurePublishLatency(hatchet_1, topic_1, payload_1, count_1) {
|
|
23
|
-
return __awaiter(this, arguments, void 0, function* (hatchet, topic, payload, count, warmupCount = 5) {
|
|
24
|
-
for (let i = 0; i < warmupCount; i += 1) {
|
|
25
|
-
yield hatchet.streams.publish(topic, payload);
|
|
26
|
-
}
|
|
27
|
-
const durationsMs = [];
|
|
28
|
-
const start = perf_hooks_1.performance.now();
|
|
29
|
-
for (let i = 0; i < count; i += 1) {
|
|
30
|
-
const before = perf_hooks_1.performance.now();
|
|
31
|
-
yield hatchet.streams.publish(topic, payload);
|
|
32
|
-
durationsMs.push(perf_hooks_1.performance.now() - before);
|
|
33
|
-
}
|
|
34
|
-
const totalMs = perf_hooks_1.performance.now() - start;
|
|
35
|
-
const sorted = [...durationsMs].sort((a, b) => a - b);
|
|
36
|
-
return {
|
|
37
|
-
count,
|
|
38
|
-
avgMs: durationsMs.reduce((sum, d) => sum + d, 0) / count,
|
|
39
|
-
p50Ms: percentile(sorted, 0.5),
|
|
40
|
-
p99Ms: percentile(sorted, 0.99),
|
|
41
|
-
maxMs: sorted[sorted.length - 1],
|
|
42
|
-
throughputPerSec: (count / totalMs) * 1000,
|
|
43
|
-
};
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
function formatPublishLatency(stats) {
|
|
47
|
-
const fmt = (ms) => ms.toFixed(2);
|
|
48
|
-
return (`avg=${fmt(stats.avgMs)}ms p50=${fmt(stats.p50Ms)}ms p99=${fmt(stats.p99Ms)}ms ` +
|
|
49
|
-
`max=${fmt(stats.maxMs)}ms throughput=${fmt(stats.throughputPerSec)}/s`);
|
|
50
|
-
}
|