@panorama-industries/effect-vercel-queue 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +13 -2
- package/dist/contracts/message-handling.d.ts +128 -0
- package/dist/contracts/message-handling.d.ts.map +1 -0
- package/dist/contracts/message-handling.js +4 -0
- package/dist/contracts/message-handling.js.map +1 -0
- package/dist/contracts/queue-api.d.ts +255 -0
- package/dist/contracts/queue-api.d.ts.map +1 -0
- package/dist/contracts/queue-api.js +18 -0
- package/dist/contracts/queue-api.js.map +1 -0
- package/dist/contracts/queue-config.d.ts +87 -0
- package/dist/contracts/queue-config.d.ts.map +1 -0
- package/dist/contracts/queue-config.js +7 -0
- package/dist/contracts/queue-config.js.map +1 -0
- package/dist/contracts/queue-consumer.d.ts +30 -0
- package/dist/contracts/queue-consumer.d.ts.map +1 -0
- package/dist/contracts/queue-consumer.js +15 -0
- package/dist/contracts/queue-consumer.js.map +1 -0
- package/dist/contracts/queue-domain.d.ts +171 -0
- package/dist/contracts/queue-domain.d.ts.map +1 -0
- package/dist/contracts/queue-domain.js +137 -0
- package/dist/contracts/queue-domain.js.map +1 -0
- package/dist/contracts/queue-poller.d.ts +169 -0
- package/dist/contracts/queue-poller.d.ts.map +1 -0
- package/dist/contracts/queue-poller.js +10 -0
- package/dist/contracts/queue-poller.js.map +1 -0
- package/dist/contracts/queue-producer.d.ts +23 -0
- package/dist/contracts/queue-producer.d.ts.map +1 -0
- package/dist/contracts/queue-producer.js +5 -0
- package/dist/contracts/queue-producer.js.map +1 -0
- package/dist/contracts/topic.d.ts +47 -0
- package/dist/contracts/topic.d.ts.map +1 -0
- package/dist/contracts/topic.js +34 -0
- package/dist/contracts/topic.js.map +1 -0
- package/dist/implementation/queue-api-live.d.ts +16 -0
- package/dist/implementation/queue-api-live.d.ts.map +1 -0
- package/dist/implementation/queue-api-live.js +326 -0
- package/dist/implementation/queue-api-live.js.map +1 -0
- package/dist/implementation/queue-config-live.d.ts +37 -0
- package/dist/implementation/queue-config-live.d.ts.map +1 -0
- package/dist/implementation/queue-config-live.js +99 -0
- package/dist/implementation/queue-config-live.js.map +1 -0
- package/dist/implementation/queue-consumer-live.d.ts +14 -0
- package/dist/implementation/queue-consumer-live.d.ts.map +1 -0
- package/dist/implementation/queue-consumer-live.js +56 -0
- package/dist/implementation/queue-consumer-live.js.map +1 -0
- package/dist/implementation/queue-live.d.ts +15 -0
- package/dist/implementation/queue-live.d.ts.map +1 -0
- package/dist/implementation/queue-live.js +16 -0
- package/dist/implementation/queue-live.js.map +1 -0
- package/dist/implementation/queue-poller-live.d.ts +14 -0
- package/dist/implementation/queue-poller-live.d.ts.map +1 -0
- package/dist/implementation/queue-poller-live.js +66 -0
- package/dist/implementation/queue-poller-live.js.map +1 -0
- package/dist/implementation/queue-producer-live.d.ts +9 -0
- package/dist/implementation/queue-producer-live.d.ts.map +1 -0
- package/dist/implementation/queue-producer-live.js +54 -0
- package/dist/implementation/queue-producer-live.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/cloud-event.d.ts +46 -0
- package/dist/internal/cloud-event.d.ts.map +1 -0
- package/dist/internal/cloud-event.js +140 -0
- package/dist/internal/cloud-event.js.map +1 -0
- package/dist/internal/lease.d.ts +23 -0
- package/dist/internal/lease.d.ts.map +1 -0
- package/dist/internal/lease.js +44 -0
- package/dist/internal/lease.js.map +1 -0
- package/dist/internal/multipart.d.ts +23 -0
- package/dist/internal/multipart.d.ts.map +1 -0
- package/dist/internal/multipart.js +205 -0
- package/dist/internal/multipart.js.map +1 -0
- package/dist/internal/process.d.ts +25 -0
- package/dist/internal/process.d.ts.map +1 -0
- package/dist/internal/process.js +95 -0
- package/dist/internal/process.js.map +1 -0
- package/dist/internal/queue-protocol.d.ts +38 -0
- package/dist/internal/queue-protocol.d.ts.map +1 -0
- package/dist/internal/queue-protocol.js +119 -0
- package/dist/internal/queue-protocol.js.map +1 -0
- package/dist/internal/version.d.ts +4 -0
- package/dist/internal/version.d.ts.map +1 -0
- package/dist/internal/version.js +4 -0
- package/dist/internal/version.js.map +1 -0
- package/dist/retry-policy.d.ts +26 -0
- package/dist/retry-policy.d.ts.map +1 -0
- package/dist/retry-policy.js +34 -0
- package/dist/retry-policy.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/test-queue.d.ts +74 -0
- package/dist/testing/test-queue.d.ts.map +1 -0
- package/dist/testing/test-queue.js +253 -0
- package/dist/testing/test-queue.js.map +1 -0
- package/package.json +59 -3
- package/src/contracts/message-handling.ts +68 -0
- package/src/contracts/queue-api.ts +199 -0
- package/src/contracts/queue-config.ts +47 -0
- package/src/contracts/queue-consumer.ts +40 -0
- package/src/contracts/queue-domain.ts +202 -0
- package/src/contracts/queue-poller.ts +76 -0
- package/src/contracts/queue-producer.ts +40 -0
- package/src/contracts/topic.ts +76 -0
- package/src/implementation/queue-api-live.ts +637 -0
- package/src/implementation/queue-config-live.ts +178 -0
- package/src/implementation/queue-consumer-live.ts +112 -0
- package/src/implementation/queue-live.ts +32 -0
- package/src/implementation/queue-poller-live.ts +130 -0
- package/src/implementation/queue-producer-live.ts +89 -0
- package/src/index.ts +19 -0
- package/src/internal/cloud-event.ts +244 -0
- package/src/internal/lease.ts +84 -0
- package/src/internal/multipart.ts +240 -0
- package/src/internal/process.ts +194 -0
- package/src/internal/queue-protocol.ts +169 -0
- package/src/internal/version.ts +5 -0
- package/src/retry-policy.ts +48 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/test-queue.ts +469 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { VercelOidc } from "@panorama-industries/effect-vercel-core";
|
|
2
|
+
import { Layer } from "effect";
|
|
3
|
+
import { HttpClient } from "effect/http";
|
|
4
|
+
import { QueueApi } from "../contracts/queue-api.ts";
|
|
5
|
+
import { QueueConfig } from "../contracts/queue-config.ts";
|
|
6
|
+
/**
|
|
7
|
+
* Implements {@link QueueApi} over HTTP with the same requests, headers and status handling as
|
|
8
|
+
* `@vercel/queue`.
|
|
9
|
+
*
|
|
10
|
+
* Requires `HttpClient`, `QueueConfig` and `VercelOidc` (used only with `QueueAuth.Oidc`). A
|
|
11
|
+
* missing OIDC token fails calls with `VercelApiError` (`ApiUnauthorized`). Acknowledging and
|
|
12
|
+
* changing visibility make up to 3 attempts when the request never reached the queue or was
|
|
13
|
+
* rate limited with a `Retry-After` delay; nothing else is retried.
|
|
14
|
+
*/
|
|
15
|
+
export declare const QueueApiLive: Layer.Layer<QueueApi, never, HttpClient.HttpClient | QueueConfig | VercelOidc>;
|
|
16
|
+
//# sourceMappingURL=queue-api-live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-api-live.d.ts","sourceRoot":"","sources":["../../src/implementation/queue-api-live.ts"],"names":[],"mappings":"AAGA,OAAO,EAKL,UAAU,EAIX,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAML,KAAK,EAON,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAgB5D,OAAO,EAAmC,QAAQ,EAAc,MAAM,2BAA2B,CAAC;AAClG,OAAO,EAAa,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAsGtE;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,KAAK,CACpC,QAAQ,EACR,KAAK,EACL,UAAU,CAAC,UAAU,GAAG,WAAW,GAAG,UAAU,CA8djD,CAAC"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { ApiRateLimited, ApiUnauthorized, ApiUnexpectedResponse, VercelApiError, VercelOidc, vercelApiErrorFromHttpClientError, vercelApiErrorFromResponse, withVercelApi, } from "@panorama-industries/effect-vercel-core";
|
|
2
|
+
import { Array as Arr, Clock, DateTime, Duration, Effect, Layer, Option, Predicate, Random, Schedule, Schema, Stream, } from "effect";
|
|
3
|
+
import { HttpClient, HttpClientRequest } from "effect/http";
|
|
4
|
+
import { BatchSendResult, HandoffOutcome, QueueApi, SendResult } from "../contracts/queue-api.js";
|
|
5
|
+
import { QueueAuth, QueueConfig } from "../contracts/queue-config.js";
|
|
6
|
+
import { BatchSizeOutOfRange, ConcurrencyCoalescedPending, ConsumerDiscoveryFailed, ConsumerRegistryNotConfigured, MessageAlreadyProcessed, MessageCorrupted, MessageHandle, MessageId, MessageLocked, MessageMetadata, MessageNotAvailable, MessageNotFound, MessageUnavailable, ReceiptHandle, ReceivedMessage, } from "../contracts/queue-domain.js";
|
|
7
|
+
import { boundaryFromContentType, decodeMultipartMixed, encodeMultipartMixed, } from "../internal/multipart.js";
|
|
8
|
+
import { HeaderSet, apiBaseUrl, coalescedPendingCount, errorBodyOf, errorCodeHeader, messageHeaders, parseDate, queuePartHeaders, retryAfterFromHeader, topicPath, wholeSeconds, } from "../internal/queue-protocol.js";
|
|
9
|
+
import { userAgent } from "../internal/version.js";
|
|
10
|
+
const defaultRetention = Duration.hours(24);
|
|
11
|
+
const leaseCallAttempts = 3;
|
|
12
|
+
const SendResponse = Schema.fromJsonString(Schema.Struct({ messageId: Schema.NullOr(Schema.String) }));
|
|
13
|
+
const BatchResponse = Schema.fromJsonString(Schema.Struct({
|
|
14
|
+
results: Schema.Array(Schema.Union([
|
|
15
|
+
Schema.Struct({ status: Schema.Literal("sent"), messageId: MessageId }),
|
|
16
|
+
Schema.Struct({ status: Schema.Literal("deferred") }),
|
|
17
|
+
Schema.Struct({
|
|
18
|
+
status: Schema.Literal("failed"),
|
|
19
|
+
statusCode: Schema.Int,
|
|
20
|
+
error: Schema.String,
|
|
21
|
+
retryable: Schema.Boolean,
|
|
22
|
+
}),
|
|
23
|
+
])),
|
|
24
|
+
}));
|
|
25
|
+
const decodeHandoffOutcome = Schema.decodeUnknownOption(HandoffOutcome);
|
|
26
|
+
const header = (response, name) => response.headers[name.toLowerCase()];
|
|
27
|
+
const unexpected = (operation, status, message) => new VercelApiError({
|
|
28
|
+
operation,
|
|
29
|
+
errorCode: Option.none(),
|
|
30
|
+
reason: new ApiUnexpectedResponse({ message, status }),
|
|
31
|
+
});
|
|
32
|
+
const isRetryableLeaseError = (error) => error instanceof VercelApiError &&
|
|
33
|
+
(Predicate.isTagged(error.reason, "ApiNetworkFailure") ||
|
|
34
|
+
(Predicate.isTagged(error.reason, "ApiRateLimited") && Option.isSome(error.reason.retryAfter)));
|
|
35
|
+
const leaseRetry = Schedule.forever.pipe(Schedule.setInputType(), Schedule.while(({ input, attempt }) => attempt < leaseCallAttempts && isRetryableLeaseError(input)), Schedule.modifyDelay(({ input, attempt }) => {
|
|
36
|
+
if (input instanceof VercelApiError &&
|
|
37
|
+
Predicate.isTagged(input.reason, "ApiRateLimited") &&
|
|
38
|
+
Option.isSome(input.reason.retryAfter)) {
|
|
39
|
+
return Effect.succeed(input.reason.retryAfter.value);
|
|
40
|
+
}
|
|
41
|
+
const base = 250 * attempt;
|
|
42
|
+
return Effect.map(Random.nextBetween(base / 2, base), Duration.millis);
|
|
43
|
+
}));
|
|
44
|
+
const maxBatchSize = 100;
|
|
45
|
+
/**
|
|
46
|
+
* Implements {@link QueueApi} over HTTP with the same requests, headers and status handling as
|
|
47
|
+
* `@vercel/queue`.
|
|
48
|
+
*
|
|
49
|
+
* Requires `HttpClient`, `QueueConfig` and `VercelOidc` (used only with `QueueAuth.Oidc`). A
|
|
50
|
+
* missing OIDC token fails calls with `VercelApiError` (`ApiUnauthorized`). Acknowledging and
|
|
51
|
+
* changing visibility make up to 3 attempts when the request never reached the queue or was
|
|
52
|
+
* rate limited with a `Retry-After` delay; nothing else is retried.
|
|
53
|
+
*/
|
|
54
|
+
export const QueueApiLive = Layer.effect(QueueApi, Effect.gen(function* () {
|
|
55
|
+
const config = yield* QueueConfig;
|
|
56
|
+
const oidc = yield* VercelOidc;
|
|
57
|
+
const httpClient = yield* HttpClient.HttpClient;
|
|
58
|
+
const token = QueueAuth.$match(config.auth, {
|
|
59
|
+
Token: ({ token }) => Effect.succeed(token),
|
|
60
|
+
Oidc: () => oidc.token,
|
|
61
|
+
});
|
|
62
|
+
const deploymentHeader = (pinned) => HttpClientRequest.setHeaders(pinned
|
|
63
|
+
? Option.match(config.deploymentId, {
|
|
64
|
+
onNone: () => ({}),
|
|
65
|
+
onSome: (id) => ({ "vqs-deployment-id": id }),
|
|
66
|
+
})
|
|
67
|
+
: {});
|
|
68
|
+
const execute = (operation, region, request) => httpClient.pipe(withVercelApi({ baseUrl: apiBaseUrl(config.baseUrl(region)), token, userAgent }), HttpClient.mapRequestEffect((request) => Effect.map(DateTime.now, (now) => HttpClientRequest.setHeader(request, "vqs-client-ts", DateTime.formatIso(now)))), (client) => client.execute(request), Effect.catchTags({
|
|
69
|
+
HttpClientError: (error) => vercelApiErrorFromHttpClientError(error, { operation, errorCodeHeader }),
|
|
70
|
+
OidcTokenUnavailable: (error) => Effect.fail(new VercelApiError({
|
|
71
|
+
operation,
|
|
72
|
+
errorCode: Option.none(),
|
|
73
|
+
reason: new ApiUnauthorized({ message: error.message }),
|
|
74
|
+
})),
|
|
75
|
+
}));
|
|
76
|
+
const readErrorBody = (response) => Effect.map(Effect.orElseSucceed(response.text, () => ""), (text) => errorBodyOf(text, header(response, "content-type")));
|
|
77
|
+
const failCommon = Effect.fnUntraced(function* (operation, response) {
|
|
78
|
+
const body = yield* readErrorBody(response);
|
|
79
|
+
if (response.status === 503 &&
|
|
80
|
+
header(response, errorCodeHeader) === "consumer_registry_not_configured") {
|
|
81
|
+
return yield* new ConsumerRegistryNotConfigured({
|
|
82
|
+
message: body.message || "Consumer registry not configured",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const now = yield* Clock.currentTimeMillis;
|
|
86
|
+
const error = yield* Effect.flip(vercelApiErrorFromResponse(response, { operation, errorCodeHeader }));
|
|
87
|
+
if (Predicate.isTagged(error.reason, "ApiRateLimited")) {
|
|
88
|
+
return yield* new VercelApiError({
|
|
89
|
+
operation: error.operation,
|
|
90
|
+
errorCode: error.errorCode,
|
|
91
|
+
reason: new ApiRateLimited({
|
|
92
|
+
message: error.reason.message,
|
|
93
|
+
retryAfter: retryAfterFromHeader(header(response, "retry-after"), now),
|
|
94
|
+
}),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return yield* error;
|
|
98
|
+
});
|
|
99
|
+
const drain = (response) => Effect.ignore(response.text);
|
|
100
|
+
const readJson = (operation, response, schema) => Effect.flatMap(Effect.catch(response.text, (error) => vercelApiErrorFromHttpClientError(error, { operation })), (text) => Effect.mapError(Schema.decodeUnknownEffect(schema)(text), (error) => unexpected(operation, response.status, `Invalid response body: ${error.message}`)));
|
|
101
|
+
const toReceivedMessage = Effect.fnUntraced(function* (part, body, location) {
|
|
102
|
+
const corrupted = (message) => new MessageCorrupted({ messageId: part.messageId, message });
|
|
103
|
+
const createdAt = yield* Option.match(parseDate(part.timestamp), {
|
|
104
|
+
onNone: () => Effect.fail(corrupted(`Invalid Vqs-Timestamp: ${part.timestamp}`)),
|
|
105
|
+
onSome: Effect.succeed,
|
|
106
|
+
});
|
|
107
|
+
const expiresAt = yield* Option.match(part.expiresAt, {
|
|
108
|
+
onNone: () => Effect.succeed(DateTime.addDuration(createdAt, defaultRetention)),
|
|
109
|
+
onSome: (raw) => Option.match(parseDate(raw), {
|
|
110
|
+
onNone: () => Effect.fail(corrupted(`Invalid Vqs-Expires-At: ${raw}`)),
|
|
111
|
+
onSome: Effect.succeed,
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
const messageId = MessageId.make(part.messageId);
|
|
115
|
+
return new ReceivedMessage({
|
|
116
|
+
handle: new MessageHandle({
|
|
117
|
+
...location,
|
|
118
|
+
messageId,
|
|
119
|
+
receiptHandle: ReceiptHandle.make(part.receiptHandle),
|
|
120
|
+
}),
|
|
121
|
+
metadata: new MessageMetadata({
|
|
122
|
+
...location,
|
|
123
|
+
messageId,
|
|
124
|
+
deliveryCount: part.deliveryCount,
|
|
125
|
+
createdAt,
|
|
126
|
+
expiresAt,
|
|
127
|
+
...Option.match(part.handoffCount, {
|
|
128
|
+
onNone: () => ({}),
|
|
129
|
+
onSome: (experimentalHandoffCount) => ({ experimentalHandoffCount }),
|
|
130
|
+
}),
|
|
131
|
+
}),
|
|
132
|
+
contentType: part.contentType,
|
|
133
|
+
body,
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
const multipartParts = (operation, response) => Option.match(Option.flatMap(Option.fromUndefinedOr(header(response, "content-type")), boundaryFromContentType), {
|
|
137
|
+
onNone: () => Stream.fail(unexpected(operation, response.status, "Expected a multipart/mixed response with a boundary")),
|
|
138
|
+
onSome: (boundary) => response.stream.pipe(decodeMultipartMixed(boundary), Stream.catchTags({
|
|
139
|
+
HttpClientError: (error) => Stream.fromEffect(vercelApiErrorFromHttpClientError(error, { operation })),
|
|
140
|
+
MultipartMixedError: (error) => Stream.fail(unexpected(operation, response.status, error.message)),
|
|
141
|
+
})),
|
|
142
|
+
});
|
|
143
|
+
const consumerHeaders = (visibilityTimeout, extra) => {
|
|
144
|
+
const headers = new HeaderSet({ accept: "multipart/mixed" });
|
|
145
|
+
for (const [name, value] of Object.entries(config.headers))
|
|
146
|
+
headers.set(name, value);
|
|
147
|
+
if (visibilityTimeout !== undefined) {
|
|
148
|
+
headers.set("vqs-visibility-timeout-seconds", String(wholeSeconds(visibilityTimeout)));
|
|
149
|
+
}
|
|
150
|
+
for (const [name, value] of Object.entries(extra))
|
|
151
|
+
headers.set(name, value);
|
|
152
|
+
return headers.toRecord();
|
|
153
|
+
};
|
|
154
|
+
const send = Effect.fn("QueueApi.send")(function* (topic, message) {
|
|
155
|
+
const operation = "QueueApi.send";
|
|
156
|
+
const request = HttpClientRequest.post(topicPath(topic)).pipe(HttpClientRequest.setHeaders(messageHeaders(config.headers, message).toRecord()), deploymentHeader(config.pinSends), HttpClientRequest.bodyUint8Array(message.body, message.contentType));
|
|
157
|
+
const response = yield* execute(operation, config.region, request);
|
|
158
|
+
if (response.status < 200 || response.status > 299) {
|
|
159
|
+
if (response.status === 502 &&
|
|
160
|
+
header(response, errorCodeHeader) === "consumer_discovery_failed") {
|
|
161
|
+
const body = yield* readErrorBody(response);
|
|
162
|
+
return yield* new ConsumerDiscoveryFailed({
|
|
163
|
+
message: body.message || "Consumer discovery failed",
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return yield* failCommon(operation, response);
|
|
167
|
+
}
|
|
168
|
+
if (response.status === 202) {
|
|
169
|
+
yield* drain(response);
|
|
170
|
+
return SendResult.Deferred();
|
|
171
|
+
}
|
|
172
|
+
const { messageId } = yield* readJson(operation, response, SendResponse);
|
|
173
|
+
if (messageId === null)
|
|
174
|
+
return SendResult.Deferred();
|
|
175
|
+
if (messageId === "") {
|
|
176
|
+
return yield* unexpected(operation, response.status, "Empty messageId in response");
|
|
177
|
+
}
|
|
178
|
+
return SendResult.Sent({ messageId: MessageId.make(messageId) });
|
|
179
|
+
});
|
|
180
|
+
const sendBatch = Effect.fn("QueueApi.sendBatch")(function* (topic, messages) {
|
|
181
|
+
const operation = "QueueApi.sendBatch";
|
|
182
|
+
if (messages.length === 0 || messages.length > maxBatchSize) {
|
|
183
|
+
return yield* new BatchSizeOutOfRange({ size: messages.length, maximum: maxBatchSize });
|
|
184
|
+
}
|
|
185
|
+
const boundary = `vqs-${crypto.randomUUID()}`;
|
|
186
|
+
const body = encodeMultipartMixed(boundary, messages.map((message) => ({
|
|
187
|
+
headers: messageHeaders(config.headers, message).sorted(),
|
|
188
|
+
body: message.body,
|
|
189
|
+
})));
|
|
190
|
+
const request = HttpClientRequest.post(topicPath(topic, "batch")).pipe(HttpClientRequest.setHeaders(config.headers), deploymentHeader(config.pinSends), HttpClientRequest.bodyUint8Array(body, `multipart/mixed; boundary=${boundary}`));
|
|
191
|
+
const response = yield* execute(operation, config.region, request);
|
|
192
|
+
if (response.status < 200 || response.status > 299) {
|
|
193
|
+
return yield* failCommon(operation, response);
|
|
194
|
+
}
|
|
195
|
+
const { results } = yield* readJson(operation, response, BatchResponse);
|
|
196
|
+
if (results.length !== messages.length) {
|
|
197
|
+
return yield* unexpected(operation, response.status, `Invalid batch response: expected ${messages.length} results, received ${results.length}`);
|
|
198
|
+
}
|
|
199
|
+
return results.map((result) => "messageId" in result
|
|
200
|
+
? BatchSendResult.Sent({ messageId: result.messageId })
|
|
201
|
+
: "statusCode" in result
|
|
202
|
+
? BatchSendResult.Failed({
|
|
203
|
+
status: result.statusCode,
|
|
204
|
+
message: result.error,
|
|
205
|
+
retryable: result.retryable,
|
|
206
|
+
})
|
|
207
|
+
: BatchSendResult.Deferred());
|
|
208
|
+
});
|
|
209
|
+
const receive = Effect.fn("QueueApi.receive")(function* (topic, consumerGroup, options = {}) {
|
|
210
|
+
const operation = "QueueApi.receive";
|
|
211
|
+
const region = options.region ?? config.region;
|
|
212
|
+
const request = HttpClientRequest.post(topicPath(topic, "consumer", consumerGroup)).pipe(HttpClientRequest.setHeaders(consumerHeaders(options.visibilityTimeout, {
|
|
213
|
+
...(options.limit === undefined ? {} : { "vqs-max-messages": String(options.limit) }),
|
|
214
|
+
...(options.cursorFallback === undefined
|
|
215
|
+
? {}
|
|
216
|
+
: { "vqs-cursor-fallback": options.cursorFallback }),
|
|
217
|
+
})), deploymentHeader(true));
|
|
218
|
+
const response = yield* execute(operation, region, request);
|
|
219
|
+
if (response.status === 204) {
|
|
220
|
+
yield* drain(response);
|
|
221
|
+
return [];
|
|
222
|
+
}
|
|
223
|
+
if (response.status < 200 || response.status > 299) {
|
|
224
|
+
return yield* failCommon(operation, response);
|
|
225
|
+
}
|
|
226
|
+
const location = { topic, consumerGroup, region };
|
|
227
|
+
const messages = yield* multipartParts(operation, response).pipe(Stream.mapEffect((part) => Option.match(queuePartHeaders(part.headers), {
|
|
228
|
+
onNone: () => Effect.as(Effect.logWarning("Missing required queue headers in multipart part"), Option.none()),
|
|
229
|
+
onSome: (headers) => toReceivedMessage(headers, part.body, location).pipe(Effect.map(Option.some), Effect.catchTag("MessageCorrupted", (error) => Effect.as(Effect.logWarning(`Skipping corrupted message ${error.messageId}: ${error.message}`), Option.none()))),
|
|
230
|
+
})), Stream.runCollect);
|
|
231
|
+
return Arr.getSomes(messages);
|
|
232
|
+
});
|
|
233
|
+
const receiveById = Effect.fn("QueueApi.receiveById")(function* (topic, consumerGroup, messageId, options = {}) {
|
|
234
|
+
const operation = "QueueApi.receiveById";
|
|
235
|
+
const region = options.region ?? config.region;
|
|
236
|
+
const request = HttpClientRequest.post(topicPath(topic, "consumer", consumerGroup, "id", messageId)).pipe(HttpClientRequest.setHeaders(consumerHeaders(options.visibilityTimeout, {})), deploymentHeader(true));
|
|
237
|
+
const response = yield* execute(operation, region, request);
|
|
238
|
+
if (response.status < 200 || response.status > 299) {
|
|
239
|
+
const body = yield* readErrorBody(response);
|
|
240
|
+
if (response.status === 404)
|
|
241
|
+
return yield* new MessageNotFound({ messageId });
|
|
242
|
+
if (response.status === 409) {
|
|
243
|
+
const now = yield* Clock.currentTimeMillis;
|
|
244
|
+
return yield* new MessageNotAvailable({
|
|
245
|
+
messageId,
|
|
246
|
+
reason: Option.match(body.originalMessageId, {
|
|
247
|
+
onNone: () => new MessageLocked({
|
|
248
|
+
retryAfter: retryAfterFromHeader(header(response, "retry-after"), now),
|
|
249
|
+
}),
|
|
250
|
+
onSome: (original) => new MessageUnavailable({
|
|
251
|
+
message: `This message was a duplicate - use originalMessageId: ${original}`,
|
|
252
|
+
}),
|
|
253
|
+
}),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (response.status === 410)
|
|
257
|
+
return yield* new MessageAlreadyProcessed({ messageId });
|
|
258
|
+
return yield* failCommon(operation, response);
|
|
259
|
+
}
|
|
260
|
+
const first = yield* Stream.runHead(multipartParts(operation, response));
|
|
261
|
+
if (Option.isNone(first))
|
|
262
|
+
return yield* new MessageNotFound({ messageId });
|
|
263
|
+
const headers = queuePartHeaders(first.value.headers);
|
|
264
|
+
if (Option.isNone(headers)) {
|
|
265
|
+
return yield* new MessageCorrupted({
|
|
266
|
+
messageId,
|
|
267
|
+
message: "Missing required queue headers in response",
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
return yield* toReceivedMessage(headers.value, first.value.body, {
|
|
271
|
+
topic,
|
|
272
|
+
consumerGroup,
|
|
273
|
+
region,
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
const leaseRequest = (operation, handle, request, defaultMessage, coalesced) => Effect.gen(function* () {
|
|
277
|
+
const response = yield* execute(operation, handle.region, request);
|
|
278
|
+
if (response.status >= 200 && response.status <= 299)
|
|
279
|
+
return response;
|
|
280
|
+
const body = yield* readErrorBody(response);
|
|
281
|
+
if (response.status === 404) {
|
|
282
|
+
return yield* new MessageNotFound({ messageId: handle.messageId });
|
|
283
|
+
}
|
|
284
|
+
if (response.status === 409) {
|
|
285
|
+
const count = coalesced
|
|
286
|
+
? coalescedPendingCount(header(response, errorCodeHeader), header(response, "vqs-experimental-coalesced"), body.text)
|
|
287
|
+
: Option.none();
|
|
288
|
+
return yield* new MessageNotAvailable({
|
|
289
|
+
messageId: handle.messageId,
|
|
290
|
+
reason: Option.match(count, {
|
|
291
|
+
onNone: () => new MessageUnavailable({ message: body.message || defaultMessage }),
|
|
292
|
+
onSome: (coalescedCount) => new ConcurrencyCoalescedPending({ coalescedCount }),
|
|
293
|
+
}),
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
return yield* failCommon(operation, response);
|
|
297
|
+
}).pipe(Effect.retry(leaseRetry));
|
|
298
|
+
const leasePath = (handle) => topicPath(handle.topic, "consumer", handle.consumerGroup, "lease", handle.receiptHandle);
|
|
299
|
+
const notAvailableMessage = "Invalid receipt handle, message not in correct state, or already processed";
|
|
300
|
+
const acknowledge = Effect.fn("QueueApi.acknowledge")(function* (handle, options = {}) {
|
|
301
|
+
const ifCoalesced = options.experimentalIfCoalesced;
|
|
302
|
+
const request = HttpClientRequest.delete(leasePath(handle)).pipe(HttpClientRequest.setHeaders(config.headers), deploymentHeader(true), HttpClientRequest.setHeaders(ifCoalesced !== undefined && ifCoalesced > 0
|
|
303
|
+
? { "vqs-experimental-if-coalesced": String(ifCoalesced) }
|
|
304
|
+
: {}));
|
|
305
|
+
const response = yield* leaseRequest("QueueApi.acknowledge", handle, request, notAvailableMessage, true);
|
|
306
|
+
yield* drain(response);
|
|
307
|
+
});
|
|
308
|
+
const changeVisibility = Effect.fn("QueueApi.changeVisibility")(function* (handle, visibilityTimeout, options = {}) {
|
|
309
|
+
const headers = new HeaderSet({ "content-type": "application/json" });
|
|
310
|
+
for (const [name, value] of Object.entries(config.headers))
|
|
311
|
+
headers.set(name, value);
|
|
312
|
+
const request = HttpClientRequest.patch(leasePath(handle)).pipe(HttpClientRequest.setHeaders(headers.toRecord()), deploymentHeader(true), HttpClientRequest.setHeaders(options.experimentalHandoff === true ? { "vqs-experimental-handoff": "1" } : {}), HttpClientRequest.bodyText(JSON.stringify({ visibilityTimeoutSeconds: wholeSeconds(visibilityTimeout) }), headers.get("content-type") ?? "application/json"));
|
|
313
|
+
const response = yield* leaseRequest("QueueApi.changeVisibility", handle, request, notAvailableMessage, false);
|
|
314
|
+
yield* drain(response);
|
|
315
|
+
return decodeHandoffOutcome(header(response, "vqs-experimental-handoff"));
|
|
316
|
+
});
|
|
317
|
+
return QueueApi.of({
|
|
318
|
+
send,
|
|
319
|
+
sendBatch,
|
|
320
|
+
receive,
|
|
321
|
+
receiveById,
|
|
322
|
+
acknowledge,
|
|
323
|
+
changeVisibility,
|
|
324
|
+
});
|
|
325
|
+
}));
|
|
326
|
+
//# sourceMappingURL=queue-api-live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-api-live.js","sourceRoot":"","sources":["../../src/implementation/queue-api-live.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DeploymentId } from "@panorama-industries/effect-vercel-core";
|
|
2
|
+
import { VercelRegion, VercelSystemEnv } from "@panorama-industries/effect-vercel-core";
|
|
3
|
+
import { Config, Layer, Redacted } from "effect";
|
|
4
|
+
import { QueueConfig } from "../contracts/queue-config.ts";
|
|
5
|
+
/** Values that replace what {@link QueueConfigLive} derives from the environment. */
|
|
6
|
+
export interface QueueConfigOptions {
|
|
7
|
+
/** Default region; otherwise `VERCEL_REGION`, then `iad1`. */
|
|
8
|
+
readonly region?: VercelRegion;
|
|
9
|
+
/** Base URL per region; replaces both the regional default and the local broker URL. */
|
|
10
|
+
readonly baseUrl?: (region: VercelRegion) => URL;
|
|
11
|
+
/** Fixed bearer token used instead of OIDC or the local broker token. */
|
|
12
|
+
readonly token?: string | Redacted.Redacted<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Deployment that sends are pinned to and consumer calls name; otherwise `VERCEL_DEPLOYMENT_ID`.
|
|
15
|
+
* `"unpinned"` sends no deployment at all, so any deployment's consumers may receive messages.
|
|
16
|
+
*/
|
|
17
|
+
readonly deploymentId?: DeploymentId | "unpinned";
|
|
18
|
+
/** Extra headers sent with every request. */
|
|
19
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Builds {@link QueueConfig} from the environment, with any given values taking precedence.
|
|
23
|
+
*
|
|
24
|
+
* Outside development, construction fails with a `ConfigError` when no deployment ID is known and
|
|
25
|
+
* the options do not opt out with `deploymentId: "unpinned"`.
|
|
26
|
+
*/
|
|
27
|
+
export declare const queueConfigLayer: (options?: QueueConfigOptions) => Layer.Layer<QueueConfig, Config.ConfigError, VercelSystemEnv>;
|
|
28
|
+
/**
|
|
29
|
+
* Derives {@link QueueConfig} from `VercelSystemEnv`, `VERCEL_QUEUE_BASE_URL` and
|
|
30
|
+
* `VERCEL_QUEUE_TOKEN`.
|
|
31
|
+
*
|
|
32
|
+
* On Vercel it targets `https://{region}.vercel-queue.com` with OIDC and pins sends to the
|
|
33
|
+
* deployment, failing with a `ConfigError` when `VERCEL_DEPLOYMENT_ID` is missing. Under
|
|
34
|
+
* `vercel dev` (CLI 59.26.0 or later) it targets the local broker with its token.
|
|
35
|
+
*/
|
|
36
|
+
export declare const QueueConfigLive: Layer.Layer<QueueConfig, Config.ConfigError, VercelSystemEnv>;
|
|
37
|
+
//# sourceMappingURL=queue-config-live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-config-live.d.ts","sourceRoot":"","sources":["../../src/implementation/queue-config-live.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,EAAE,MAAM,EAA0B,KAAK,EAAU,QAAQ,EAAU,MAAM,QAAQ,CAAC;AAEzF,OAAO,EAAa,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEtE,qFAAqF;AACrF,MAAM,WAAW,kBAAkB;IACjC,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAE/B,wFAAwF;IACxF,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,GAAG,CAAC;IAEjD,yEAAyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEpD;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IAElD,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrD;AAmID;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aAClB,kBAAkB,KAC1B,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,eAAe,CACP,CAAC;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,eAAe,CACtE,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { VercelRegion, VercelSystemEnv } from "@panorama-industries/effect-vercel-core";
|
|
2
|
+
import { Config, ConfigProvider, Effect, Layer, Option, Redacted, Schema } from "effect";
|
|
3
|
+
import { QueueAuth, QueueConfig } from "../contracts/queue-config.js";
|
|
4
|
+
const defaultRegion = VercelRegion.make("iad1");
|
|
5
|
+
const semver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\da-zA-Z-]+(?:\.[\da-zA-Z-]+)*))?(?:\+[\da-zA-Z-]+(?:\.[\da-zA-Z-]+)*)?$/;
|
|
6
|
+
const supportsLocalQueueBroker = (version) => {
|
|
7
|
+
if (version.length > 256)
|
|
8
|
+
return false;
|
|
9
|
+
const match = semver.exec(version);
|
|
10
|
+
if (match === null)
|
|
11
|
+
return false;
|
|
12
|
+
const major = Number(match[1]);
|
|
13
|
+
const minor = Number(match[2]);
|
|
14
|
+
const patch = Number(match[3]);
|
|
15
|
+
const prerelease = match[4];
|
|
16
|
+
if (![major, minor, patch].every(Number.isSafeInteger) ||
|
|
17
|
+
prerelease?.split(".").some((part) => /^0\d+$/.test(part))) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return (major > 59 ||
|
|
21
|
+
(major === 59 && (minor > 26 || (minor === 26 && (patch > 0 || prerelease === undefined)))));
|
|
22
|
+
};
|
|
23
|
+
const configError = (message) => new Config.ConfigError(new ConfigProvider.SourceError({ message }));
|
|
24
|
+
const nonEmpty = (name) => Config.option(Config.String(name)).pipe(Config.map(Option.filter((value) => value !== "")));
|
|
25
|
+
const decodeUrl = Schema.decodeUnknownOption(Schema.URLFromString);
|
|
26
|
+
const regionalBaseUrl = (region) => new URL(`https://${region}.vercel-queue.com`);
|
|
27
|
+
const stripTrailingSlashes = (path) => path.replace(/\/+$/, "");
|
|
28
|
+
const sameEndpoint = (a, b) => a.origin === b.origin && stripTrailingSlashes(a.pathname) === stripTrailingSlashes(b.pathname);
|
|
29
|
+
const missingDeploymentId = configError("No deployment ID available. VERCEL_DEPLOYMENT_ID is not set.\n\n" +
|
|
30
|
+
"This usually means the code is running outside a Vercel deployment " +
|
|
31
|
+
"(e.g. during build or in a non-Vercel environment).\n\n" +
|
|
32
|
+
"To fix this, provide an explicit deployment ID:\n" +
|
|
33
|
+
' queueConfigLayer({ deploymentId: DeploymentId.make("dpl_xxx") })\n' +
|
|
34
|
+
"Or explicitly opt out of deployment pinning:\n" +
|
|
35
|
+
' queueConfigLayer({ deploymentId: "unpinned" })');
|
|
36
|
+
const missingLocalToken = configError("Missing local queue token. VERCEL_QUEUE_BASE_URL selects a local broker, " +
|
|
37
|
+
"but VERCEL_QUEUE_TOKEN is not set. Start your app with a Vercel CLI " +
|
|
38
|
+
"version that supports local Queues, or provide an explicit token.");
|
|
39
|
+
const localToken = Config.option(Config.Redacted("VERCEL_QUEUE_TOKEN")).pipe(Effect.map(Option.filter((token) => Redacted.value(token) !== "")), Effect.flatMap(Option.match({ onNone: () => Effect.fail(missingLocalToken), onSome: Effect.succeed })));
|
|
40
|
+
const invalidLocalUrl = configError("Invalid VERCEL_QUEUE_BASE_URL: expected an absolute URL");
|
|
41
|
+
const resolveQueueConfig = Effect.fnUntraced(function* (options) {
|
|
42
|
+
const env = yield* VercelSystemEnv;
|
|
43
|
+
const devMode = env.isDevelopment && Option.isNone(env.deploymentId);
|
|
44
|
+
const region = options.region ??
|
|
45
|
+
Option.getOrUndefined(env.region) ??
|
|
46
|
+
(yield* Effect.as(devMode
|
|
47
|
+
? Effect.void
|
|
48
|
+
: Effect.logWarning(`Queue region not detected; defaulting to "${defaultRegion}". On Vercel it comes ` +
|
|
49
|
+
"from VERCEL_REGION. Set it explicitly with queueConfigLayer({ region }) to " +
|
|
50
|
+
"silence this warning."), defaultRegion));
|
|
51
|
+
const injectedUrl = devMode && Option.exists(env.cliVersion, supportsLocalQueueBroker)
|
|
52
|
+
? yield* nonEmpty("VERCEL_QUEUE_BASE_URL")
|
|
53
|
+
: Option.none();
|
|
54
|
+
const localUrl = Option.flatMap(injectedUrl, decodeUrl);
|
|
55
|
+
if (Option.isSome(injectedUrl) && Option.isNone(localUrl) && options.baseUrl === undefined) {
|
|
56
|
+
return yield* Effect.fail(invalidLocalUrl);
|
|
57
|
+
}
|
|
58
|
+
const baseUrl = options.baseUrl ??
|
|
59
|
+
Option.match(localUrl, {
|
|
60
|
+
onNone: () => regionalBaseUrl,
|
|
61
|
+
onSome: (url) => () => new URL(url),
|
|
62
|
+
});
|
|
63
|
+
const usesLocalBroker = Option.exists(localUrl, (url) => sameEndpoint(baseUrl(region), url));
|
|
64
|
+
const auth = options.token !== undefined
|
|
65
|
+
? QueueAuth.Token({
|
|
66
|
+
token: Redacted.isRedacted(options.token) ? options.token : Redacted.make(options.token),
|
|
67
|
+
})
|
|
68
|
+
: usesLocalBroker
|
|
69
|
+
? QueueAuth.Token({ token: yield* localToken })
|
|
70
|
+
: QueueAuth.Oidc();
|
|
71
|
+
const deploymentId = options.deploymentId === "unpinned" || usesLocalBroker || devMode
|
|
72
|
+
? Option.none()
|
|
73
|
+
: Option.some(yield* Option.match(Option.orElse(Option.fromUndefinedOr(options.deploymentId), () => env.deploymentId), { onNone: () => Effect.fail(missingDeploymentId), onSome: Effect.succeed }));
|
|
74
|
+
return QueueConfig.of({
|
|
75
|
+
region,
|
|
76
|
+
baseUrl,
|
|
77
|
+
auth,
|
|
78
|
+
deploymentId,
|
|
79
|
+
pinSends: Option.isSome(deploymentId),
|
|
80
|
+
headers: options.headers ?? {},
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* Builds {@link QueueConfig} from the environment, with any given values taking precedence.
|
|
85
|
+
*
|
|
86
|
+
* Outside development, construction fails with a `ConfigError` when no deployment ID is known and
|
|
87
|
+
* the options do not opt out with `deploymentId: "unpinned"`.
|
|
88
|
+
*/
|
|
89
|
+
export const queueConfigLayer = (options = {}) => Layer.effect(QueueConfig, resolveQueueConfig(options));
|
|
90
|
+
/**
|
|
91
|
+
* Derives {@link QueueConfig} from `VercelSystemEnv`, `VERCEL_QUEUE_BASE_URL` and
|
|
92
|
+
* `VERCEL_QUEUE_TOKEN`.
|
|
93
|
+
*
|
|
94
|
+
* On Vercel it targets `https://{region}.vercel-queue.com` with OIDC and pins sends to the
|
|
95
|
+
* deployment, failing with a `ConfigError` when `VERCEL_DEPLOYMENT_ID` is missing. Under
|
|
96
|
+
* `vercel dev` (CLI 59.26.0 or later) it targets the local broker with its token.
|
|
97
|
+
*/
|
|
98
|
+
export const QueueConfigLive = queueConfigLayer();
|
|
99
|
+
//# sourceMappingURL=queue-config-live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-config-live.js","sourceRoot":"","sources":["../../src/implementation/queue-config-live.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import { QueueApi } from "../contracts/queue-api.ts";
|
|
3
|
+
import { QueueConfig } from "../contracts/queue-config.ts";
|
|
4
|
+
import { QueueConsumer } from "../contracts/queue-consumer.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Implements {@link QueueConsumer} for push delivery, as `@vercel/queue`'s `handleCallback`.
|
|
7
|
+
*
|
|
8
|
+
* Requires `QueueApi` and `QueueConfig`. Leases default to 5 minutes (at least 30 seconds) and are
|
|
9
|
+
* renewed while the handler runs. Responses: 200 `{status:"success"}`; 200 `{status:"skipped"}`
|
|
10
|
+
* when the message was already processed (410) or is held elsewhere (409); 400 `{error}` for a
|
|
11
|
+
* malformed CloudEvent; 500 otherwise, so the queue redelivers.
|
|
12
|
+
*/
|
|
13
|
+
export declare const QueueConsumerLive: Layer.Layer<QueueConsumer, never, QueueApi | QueueConfig>;
|
|
14
|
+
//# sourceMappingURL=queue-consumer-live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-consumer-live.d.ts","sourceRoot":"","sources":["../../src/implementation/queue-consumer-live.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,EAAqB,MAAM,QAAQ,CAAC;AASjE,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAuB/D;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,2DAmE7B,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Cause, Effect, Layer, Option, Predicate } from "effect";
|
|
2
|
+
import { HttpServerRequest, HttpServerResponse } from "effect/http";
|
|
3
|
+
import { QueueApi } from "../contracts/queue-api.js";
|
|
4
|
+
import { QueueConfig } from "../contracts/queue-config.js";
|
|
5
|
+
import { QueueConsumer } from "../contracts/queue-consumer.js";
|
|
6
|
+
import { inlineDelivery, MalformedCloudEvent, parseCallback } from "../internal/cloud-event.js";
|
|
7
|
+
import { leaseVisibilityTimeout } from "../internal/lease.js";
|
|
8
|
+
import { processDelivery, producerLinks, withProcessSpan } from "../internal/process.js";
|
|
9
|
+
const skipped = (reason, messageId) => Effect.logDebug(`Queue callback skipped (${reason}) for message ${messageId}: ` +
|
|
10
|
+
"the message was already handled or is no longer available to this consumer.").pipe(Effect.as(HttpServerResponse.jsonUnsafe({ status: "skipped", reason, messageId })));
|
|
11
|
+
const failed = (cause) => Cause.hasInterruptsOnly(cause)
|
|
12
|
+
? Effect.failCause(cause)
|
|
13
|
+
: Effect.logError("Queue callback error", cause).pipe(Effect.as(HttpServerResponse.jsonUnsafe({ error: "Failed to process queue message" }, { status: 500 })));
|
|
14
|
+
/**
|
|
15
|
+
* Implements {@link QueueConsumer} for push delivery, as `@vercel/queue`'s `handleCallback`.
|
|
16
|
+
*
|
|
17
|
+
* Requires `QueueApi` and `QueueConfig`. Leases default to 5 minutes (at least 30 seconds) and are
|
|
18
|
+
* renewed while the handler runs. Responses: 200 `{status:"success"}`; 200 `{status:"skipped"}`
|
|
19
|
+
* when the message was already processed (410) or is held elsewhere (409); 400 `{error}` for a
|
|
20
|
+
* malformed CloudEvent; 500 otherwise, so the queue redelivers.
|
|
21
|
+
*/
|
|
22
|
+
export const QueueConsumerLive = Layer.effect(QueueConsumer, Effect.gen(function* () {
|
|
23
|
+
const api = yield* QueueApi;
|
|
24
|
+
const config = yield* QueueConfig;
|
|
25
|
+
const handler = (topic, handle, options = {}) => Effect.gen(function* () {
|
|
26
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
27
|
+
const parsed = yield* parseCallback(request.headers, request.text);
|
|
28
|
+
const region = Option.getOrElse(parsed.region, () => config.region);
|
|
29
|
+
const delivery = Option.match(parsed.inline, {
|
|
30
|
+
onNone: () => api
|
|
31
|
+
.receiveById(parsed.topic, parsed.consumerGroup, parsed.messageId, {
|
|
32
|
+
visibilityTimeout: leaseVisibilityTimeout(options.visibilityTimeout),
|
|
33
|
+
region,
|
|
34
|
+
})
|
|
35
|
+
.pipe(Effect.map((message) => ({ message, deadline: Option.none() }))),
|
|
36
|
+
onSome: (inline) => Effect.flatMap(request.arrayBuffer, (buffer) => buffer.byteLength === 0
|
|
37
|
+
? Effect.fail(new MalformedCloudEvent({
|
|
38
|
+
message: "Binary mode callback with receipt handle is missing payload",
|
|
39
|
+
}))
|
|
40
|
+
: inlineDelivery(parsed, inline, region, topic.contentType, new Uint8Array(buffer))),
|
|
41
|
+
});
|
|
42
|
+
return yield* delivery.pipe(Effect.flatMap((received) => processDelivery(api, topic, handle, options, received)), withProcessSpan(producerLinks(request.headers)), Effect.as(HttpServerResponse.jsonUnsafe({ status: "success" })), Effect.catch((error) => {
|
|
43
|
+
if (Predicate.isTagged(error, "MessageAlreadyProcessed")) {
|
|
44
|
+
return skipped("already_processed", parsed.messageId);
|
|
45
|
+
}
|
|
46
|
+
if (Predicate.isTagged(error, "MessageNotAvailable")) {
|
|
47
|
+
return skipped("not_available", parsed.messageId);
|
|
48
|
+
}
|
|
49
|
+
return Effect.fail(error);
|
|
50
|
+
}));
|
|
51
|
+
}).pipe(Effect.catch((error) => error instanceof MalformedCloudEvent
|
|
52
|
+
? Effect.logError("Queue callback error", error).pipe(Effect.as(HttpServerResponse.jsonUnsafe({ error: error.message }, { status: 400 })))
|
|
53
|
+
: Effect.fail(error)), Effect.catchCause(failed), Effect.annotateLogs({ module: "QueueConsumer" }));
|
|
54
|
+
return QueueConsumer.of({ handler });
|
|
55
|
+
}));
|
|
56
|
+
//# sourceMappingURL=queue-consumer-live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-consumer-live.js","sourceRoot":"","sources":["../../src/implementation/queue-consumer-live.ts"],"names":[],"mappings":"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"}
|