@dbos-inc/sqs-receive 3.0.10-preview
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/README.md +178 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +167 -0
- package/dist/index.js.map +1 -0
- package/dist/sqs.test.d.ts +2 -0
- package/dist/sqs.test.d.ts.map +1 -0
- package/dist/sqs.test.js +108 -0
- package/dist/sqs.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/index.ts +226 -0
- package/jest.config.js +8 -0
- package/package.json +34 -0
- package/sqs-test-dbos-config.yaml +10 -0
- package/sqs.test.ts +111 -0
- package/tsconfig.json +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# DBOS AWS Simple Queue Service (SQS) Receiver
|
|
2
|
+
|
|
3
|
+
Message queues are a common building block for distributed systems. Message queues allow processing to occur at a different place or time, perhaps in another programming environment. Due to its flexibility, robustness, integration, and low cost, [Amazon Simple Queue Service](https://aws.amazon.com/sqs/) is the most popular message queuing service underpinning distributed systems in AWS.
|
|
4
|
+
|
|
5
|
+
This package includes a [DBOS](https://docs.dbos.dev/) receiver for SQS messages, which invokes a workflow for each message received.
|
|
6
|
+
|
|
7
|
+
The test in this package also shows wrapping SQS send in a [DBOS step](https://docs.dbos.dev/typescript/tutorials/step-tutorial).
|
|
8
|
+
|
|
9
|
+
## Getting Started
|
|
10
|
+
|
|
11
|
+
In order to send and receive messages with SQS, it is necessary to register with AWS, create a queue, and create access keys for the queue. (See [Send Messages Between Distributed Applications](https://aws.amazon.com/getting-started/hands-on/send-messages-distributed-applications/) in AWS documentation.)
|
|
12
|
+
|
|
13
|
+
## Configuring a DBOS Application with AWS SQS
|
|
14
|
+
|
|
15
|
+
First, ensure that the DBOS SQS package is installed into the application:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
npm install @dbos-inc/sqs-receive
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Receiving Messages
|
|
22
|
+
|
|
23
|
+
The DBOS SQS receiver provides the capability of running DBOS workflows exactly once per SQS message, even on standard "at-least-once" SQS queues.
|
|
24
|
+
|
|
25
|
+
The package uses decorators to configure message receipt and identify the functions that will be invoked during message dispatch.
|
|
26
|
+
|
|
27
|
+
### Imports
|
|
28
|
+
|
|
29
|
+
First, ensure that the SQS receiver class is imported:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { SQSReceiver } from '@dbos-inc/dbos-sqs';
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Receiver Configuration
|
|
36
|
+
|
|
37
|
+
Receiving messages requires:
|
|
38
|
+
|
|
39
|
+
- Creating an `SQSReceiver` object
|
|
40
|
+
- Providing configuration, so that the receiver can connect to AWS and locate the SQS queues
|
|
41
|
+
- Associating your workflow code with SQS message queues
|
|
42
|
+
- Registering your receiver with DBOS
|
|
43
|
+
|
|
44
|
+
The SQS Receiver can be configured in 3 ways:
|
|
45
|
+
|
|
46
|
+
- When constructing the `SQSReceiver` object
|
|
47
|
+
- At the class level, with `@<receiver>.configuration`
|
|
48
|
+
- At the method level, with `@<receiver>.messageConsumer`
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Note the configuration interface is:
|
|
52
|
+
interface SQSConfig {
|
|
53
|
+
client?: SQSClient | (()=>SQSClient);
|
|
54
|
+
queueUrl?: string;
|
|
55
|
+
getWorkflowKey?: (m: Message) => string;
|
|
56
|
+
workflowQueueName?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Create a receiver (can configure now, or later...)
|
|
60
|
+
const sqsReceiver = new SQSReceiver();
|
|
61
|
+
|
|
62
|
+
// Optionally, configure the receiver at the class level
|
|
63
|
+
@sqsReceiver.configure({client: .../*client or function to retrieve client goes here*/})
|
|
64
|
+
class SQSEventProcessor {
|
|
65
|
+
...
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then, within the class, one or more `static` workflow methods should be decorated with `@sqsReceiver.messageConsumer` to handle SQS messages:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
@sqsReceiver.configure(...)
|
|
73
|
+
class SQSEventProcessor {
|
|
74
|
+
@sqsReceiver.messageConsumer({ queueUrl: process.env['SQS_QUEUE_URL'] })
|
|
75
|
+
@DBOS.workflow()
|
|
76
|
+
static async recvMessage(msg: Message) {
|
|
77
|
+
// Workflow code goes here...
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Finally, register your SQS receiver, and launch DBOS:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
DBOS.registerLifecycleCallback(sqsReceiver);
|
|
86
|
+
await DBOS.launch();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
_NOTE:_ The DBOS `@messageConsumer` decorator should be applied to a method decorated with `@DBOS.workflow`.
|
|
90
|
+
|
|
91
|
+
### Concurrency and Rate Limiting
|
|
92
|
+
|
|
93
|
+
By default, `@messageConsumer` workflows are started immediately after message receipt. If `workflowQueueName` is specified in the `SQSConfig` at either the method, class, or receiver level, then the workflow will be enqueued in a [workflow queue](https://docs.dbos.dev/typescript/reference/transactapi/workflow-queues).
|
|
94
|
+
|
|
95
|
+
### Once-And-Only-Once (OAOO) Semantics
|
|
96
|
+
|
|
97
|
+
Typical application processing for standard SQS queues implements "at least once" processing of the message:
|
|
98
|
+
|
|
99
|
+
- Receive the message from the SQS queue
|
|
100
|
+
- If necessary, extend the visibility timeout of the message during the course of processing
|
|
101
|
+
- After all processing is complete, delete the message from the queue. If there are any failures,
|
|
102
|
+
the message will remain in the queue and be redelivered to another consumer.
|
|
103
|
+
|
|
104
|
+
The DBOS receiver proceeds differently:
|
|
105
|
+
|
|
106
|
+
- Receive the message from the SQS queue
|
|
107
|
+
- Start a workflow (using an OAOO key computed from the message)
|
|
108
|
+
- Quickly delete the message
|
|
109
|
+
|
|
110
|
+
This means that, instead of the SQS service redelivering the message in the case of a transient failure, it is up to DBOS to restart any interrupted workflows. Also, since DBOS workflows execute to completion exactly once, it is not necessary to use a SQS FIFO queue for exactly-once processing.
|
|
111
|
+
|
|
112
|
+
## Simple Testing
|
|
113
|
+
|
|
114
|
+
The `sqs.test.ts` file included in the source repository demonstrates sending and processing SQS messages. Before running, set the following environment variables:
|
|
115
|
+
|
|
116
|
+
- `SQS_QUEUE_URL`: SQS queue URL with access for sending and receiving messages
|
|
117
|
+
- `AWS_ENDPOINT_URL_SQS`: SQS endpoint URL
|
|
118
|
+
- `AWS_REGION`: AWS region to use
|
|
119
|
+
- `AWS_ACCESS_KEY_ID`: The access key with permission to use the SQS service
|
|
120
|
+
- `AWS_SECRET_ACCESS_KEY`: The secret access key corresponding to `AWS_ACCESS_KEY_ID`
|
|
121
|
+
|
|
122
|
+
## Sending Messages
|
|
123
|
+
|
|
124
|
+
Sending messages in DBOS is done using the AWS libraries directly, with the send call wrapped in a DBOS step to make execution durable.
|
|
125
|
+
|
|
126
|
+
### Imports
|
|
127
|
+
|
|
128
|
+
First, ensure that the AWS libraries are imported:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { Message, SendMessageCommand, SendMessageCommandInput, SQSClient } from '@aws-sdk/client-sqs';
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Sending Code
|
|
135
|
+
|
|
136
|
+
The code below is just an example. You may choose to create your SQS client and message sending code differently; the key here is that it is registered with DBOS:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// Your preferred method for connecting to SQS
|
|
140
|
+
function createSQS() {
|
|
141
|
+
return new SQSClient({
|
|
142
|
+
region: process.env['AWS_REGION'] ?? '',
|
|
143
|
+
endpoint: process.env['AWS_ENDPOINT_URL_SQS'],
|
|
144
|
+
credentials: {
|
|
145
|
+
accessKeyId: process.env['AWS_ACCESS_KEY_ID'] ?? '',
|
|
146
|
+
secretAccessKey: process.env['AWS_SECRET_ACCESS_KEY'] ?? '',
|
|
147
|
+
},
|
|
148
|
+
//logger: console,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Maybe you have the URL in each message, or maybe set globally...
|
|
153
|
+
// Create a new type that omits the QueueUrl property
|
|
154
|
+
type MessageWithoutQueueUrl = Omit<SendMessageCommandInput, 'QueueUrl'>;
|
|
155
|
+
|
|
156
|
+
// Create a new type that allows QueueUrl to be added later
|
|
157
|
+
type MessageWithOptionalQueueUrl = MessageWithoutQueueUrl & { QueueUrl?: string };
|
|
158
|
+
|
|
159
|
+
// This is the send code, not to be called directly...
|
|
160
|
+
async function sendMessageInternal(msg: MessageWithOptionalQueueUrl) {
|
|
161
|
+
try {
|
|
162
|
+
const smsg = { ...msg, QueueUrl: msg.QueueUrl || process.env['SQS_QUEUE_URL']! };
|
|
163
|
+
return await createSQS().send(new SendMessageCommand(smsg));
|
|
164
|
+
} catch (e) {
|
|
165
|
+
DBOS.logger.error(e);
|
|
166
|
+
throw e;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// `sendMessageStep(msg)` will be what your workflows actually call.
|
|
171
|
+
const sendMessageStep = DBOS.registerStep(sendMessageInternal, { name: 'Send SQS Message' });
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Next Steps
|
|
175
|
+
|
|
176
|
+
- To start a DBOS app from a template, visit our [quickstart](https://docs.dbos.dev/quickstart).
|
|
177
|
+
- For DBOS programming tutorials, check out our [programming guide](https://docs.dbos.dev/typescript/programming-guide).
|
|
178
|
+
- To learn more about DBOS, take a look at [our documentation](https://docs.dbos.dev/) or our [source code](https://github.com/dbos-inc/dbos-transact-ts).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DBOSLifecycleCallback } from '@dbos-inc/dbos-sdk';
|
|
2
|
+
import { Message, ReceiveMessageCommand, ReceiveMessageCommandOutput, SQSClient } from '@aws-sdk/client-sqs';
|
|
3
|
+
interface SQSConfig {
|
|
4
|
+
client?: SQSClient | (() => SQSClient);
|
|
5
|
+
queueUrl?: string;
|
|
6
|
+
getWorkflowKey?: (m: Message) => string;
|
|
7
|
+
workflowQueueName?: string;
|
|
8
|
+
}
|
|
9
|
+
declare class SQSReceiver extends DBOSLifecycleCallback {
|
|
10
|
+
config?: SQSConfig;
|
|
11
|
+
constructor(config?: SQSConfig);
|
|
12
|
+
listeners: Promise<void>[];
|
|
13
|
+
isShuttingDown: boolean;
|
|
14
|
+
destroy(): Promise<void>;
|
|
15
|
+
static sendReceiveMessageCommandSafe(sqs: SQSClient, params: ReceiveMessageCommand): Promise<ReceiveMessageCommandOutput>;
|
|
16
|
+
static validateConnection(client: SQSClient, url: string): Promise<void>;
|
|
17
|
+
initialize(): Promise<void>;
|
|
18
|
+
logRegisteredEndpoints(): void;
|
|
19
|
+
configuration(config: SQSConfig): <T extends new (...args: unknown[]) => object>(ctor: T) => void;
|
|
20
|
+
messageConsumer(config?: SQSConfig): <This, Args extends [Message], Return>(target: object, propertyKey: string, inDescriptor: TypedPropertyDescriptor<(this: This, ...args: Args) => Promise<Return>>) => TypedPropertyDescriptor<(this: This, ...args: Args) => Promise<Return>>;
|
|
21
|
+
}
|
|
22
|
+
export { SQSConfig, SQSReceiver };
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAErF,OAAO,EAIL,OAAO,EACP,qBAAqB,EACrB,2BAA2B,EAC3B,SAAS,EACV,MAAM,qBAAqB,CAAC;AAE7B,UAAU,SAAS;IACjB,MAAM,CAAC,EAAE,SAAS,GAAG,CAAC,MAAM,SAAS,CAAC,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IACxC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAUD,cAAM,WAAY,SAAQ,qBAAqB;IAC7C,MAAM,CAAC,EAAE,SAAS,CAAC;gBAEP,MAAM,CAAC,EAAE,SAAS;IAK9B,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAM;IAChC,cAAc,UAAS;IAER,OAAO;WAWT,6BAA6B,CACxC,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,2BAA2B,CAAC;WAS1B,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM;IAS/C,UAAU;IAoGhB,sBAAsB;IAqB/B,aAAa,CAAC,MAAM,EAAE,SAAS,4BAIa,OAAO,EAAE,KAAG,MAAM,QAAU,CAAC;IAQzE,eAAe,CAAC,MAAM,CAAC,EAAE,SAAS,kDAItB,MAAM,eACD,MAAM,gBACL,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,QAAQ,MAAM,CAAC,CAAC,oCAAxC,IAAI,WAAW,IAAI,KAAK,QAAQ,MAAM,CAAC;CAczF;AAED,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SQSReceiver = void 0;
|
|
4
|
+
const dbos_sdk_1 = require("@dbos-inc/dbos-sdk");
|
|
5
|
+
const client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
6
|
+
class SQSReceiver extends dbos_sdk_1.DBOSLifecycleCallback {
|
|
7
|
+
config;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
super();
|
|
10
|
+
this.config = config;
|
|
11
|
+
}
|
|
12
|
+
listeners = [];
|
|
13
|
+
isShuttingDown = false;
|
|
14
|
+
async destroy() {
|
|
15
|
+
this.isShuttingDown = true;
|
|
16
|
+
try {
|
|
17
|
+
await Promise.allSettled(this.listeners);
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
// yawn
|
|
21
|
+
}
|
|
22
|
+
this.listeners = [];
|
|
23
|
+
}
|
|
24
|
+
// async function that uses .then/.catch to handle potentially unreliable library calls
|
|
25
|
+
static async sendReceiveMessageCommandSafe(sqs, params) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
sqs
|
|
28
|
+
.send(params)
|
|
29
|
+
.then((response) => resolve(response))
|
|
30
|
+
.catch((error) => reject(error));
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
static async validateConnection(client, url) {
|
|
34
|
+
const params = {
|
|
35
|
+
QueueUrl: url,
|
|
36
|
+
AttributeNames: ['All'],
|
|
37
|
+
};
|
|
38
|
+
const _validateSQSConfiguration = await client.send(new client_sqs_1.GetQueueAttributesCommand(params));
|
|
39
|
+
}
|
|
40
|
+
async initialize() {
|
|
41
|
+
const regops = dbos_sdk_1.DBOS.getAssociatedInfo(this);
|
|
42
|
+
for (const regop of regops) {
|
|
43
|
+
const { methodConfig, classConfig, methodReg } = regop;
|
|
44
|
+
const sqsclass = classConfig;
|
|
45
|
+
const sqsmethod = methodConfig;
|
|
46
|
+
if (!sqsmethod)
|
|
47
|
+
continue;
|
|
48
|
+
const url = sqsclass.config?.queueUrl ?? sqsmethod.config?.queueUrl ?? this.config?.queueUrl;
|
|
49
|
+
if (!url)
|
|
50
|
+
continue;
|
|
51
|
+
const cname = methodReg.className;
|
|
52
|
+
const mname = methodReg.name;
|
|
53
|
+
if (!methodReg.workflowConfig) {
|
|
54
|
+
throw new dbos_sdk_1.Error.DBOSError(`Error registering method ${cname}.${mname}: An SQS decorator can only be assigned to a workflow!`);
|
|
55
|
+
}
|
|
56
|
+
let sqs = undefined;
|
|
57
|
+
if (sqsmethod.config?.client) {
|
|
58
|
+
sqs = typeof sqsmethod.config.client === 'function' ? sqsmethod.config.client() : sqsmethod.config.client;
|
|
59
|
+
}
|
|
60
|
+
else if (sqsclass.config?.client) {
|
|
61
|
+
sqs = typeof sqsclass.config.client === 'function' ? sqsclass.config.client() : sqsclass.config.client;
|
|
62
|
+
}
|
|
63
|
+
else if (this.config?.client) {
|
|
64
|
+
sqs = typeof this.config.client === 'function' ? this.config.client() : this.config.client;
|
|
65
|
+
}
|
|
66
|
+
if (!sqs) {
|
|
67
|
+
throw new dbos_sdk_1.Error.DBOSError(`Error initializing SQS method ${cname}.${mname}: No SQSClient provided`);
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
await SQSReceiver.validateConnection(sqs, url);
|
|
71
|
+
dbos_sdk_1.DBOS.logger.info(`Successfully connected to SQS queue ${url} for ${cname}.${mname}`);
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
const err = e;
|
|
75
|
+
dbos_sdk_1.DBOS.logger.error(err);
|
|
76
|
+
throw new dbos_sdk_1.Error.DBOSError(`SQS Receiver for ${cname}.${mname} was unable to connect to ${url}: ${err.message}`);
|
|
77
|
+
}
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
79
|
+
const sqsr = this;
|
|
80
|
+
this.listeners.push((async (client, url) => {
|
|
81
|
+
while (!this.isShuttingDown) {
|
|
82
|
+
// Get message
|
|
83
|
+
try {
|
|
84
|
+
const response = await SQSReceiver.sendReceiveMessageCommandSafe(client, new client_sqs_1.ReceiveMessageCommand({
|
|
85
|
+
QueueUrl: url,
|
|
86
|
+
MaxNumberOfMessages: 1,
|
|
87
|
+
WaitTimeSeconds: 5,
|
|
88
|
+
}));
|
|
89
|
+
if (!response.Messages || response.Messages.length === 0) {
|
|
90
|
+
dbos_sdk_1.DBOS.logger.debug(`No messages for ${url} - `);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const message = response.Messages[0];
|
|
94
|
+
// Start workflow
|
|
95
|
+
let wfid = sqsmethod.config?.getWorkflowKey ? sqsmethod.config.getWorkflowKey(message) : undefined;
|
|
96
|
+
if (!wfid) {
|
|
97
|
+
wfid = sqsclass.config?.getWorkflowKey ? sqsclass.config.getWorkflowKey(message) : undefined;
|
|
98
|
+
}
|
|
99
|
+
if (!wfid) {
|
|
100
|
+
wfid = sqsr.config?.getWorkflowKey ? sqsr.config.getWorkflowKey(message) : undefined;
|
|
101
|
+
}
|
|
102
|
+
if (!wfid)
|
|
103
|
+
wfid = message.MessageId;
|
|
104
|
+
await dbos_sdk_1.DBOS.startWorkflow(methodReg.registeredFunction, {
|
|
105
|
+
workflowID: wfid,
|
|
106
|
+
queueName: sqsmethod.config?.workflowQueueName ??
|
|
107
|
+
sqsclass.config?.workflowQueueName ??
|
|
108
|
+
sqsr.config?.workflowQueueName,
|
|
109
|
+
})(message);
|
|
110
|
+
// Delete the message from the queue after starting workflow (which will take over retries)
|
|
111
|
+
await client.send(new client_sqs_1.DeleteMessageCommand({
|
|
112
|
+
QueueUrl: url,
|
|
113
|
+
ReceiptHandle: message.ReceiptHandle,
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
dbos_sdk_1.DBOS.logger.error(e);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
})(sqs, url));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
logRegisteredEndpoints() {
|
|
124
|
+
dbos_sdk_1.DBOS.logger.info('SQS receiver endpoints:');
|
|
125
|
+
const eps = dbos_sdk_1.DBOS.getAssociatedInfo(this);
|
|
126
|
+
for (const e of eps) {
|
|
127
|
+
const { methodConfig, classConfig, methodReg } = e;
|
|
128
|
+
const sqsclass = classConfig;
|
|
129
|
+
const sqsmethod = methodConfig;
|
|
130
|
+
if (sqsmethod) {
|
|
131
|
+
const url = sqsclass.config?.queueUrl ?? sqsmethod.config?.queueUrl ?? this.config?.queueUrl;
|
|
132
|
+
if (url) {
|
|
133
|
+
const cname = methodReg.className;
|
|
134
|
+
const mname = methodReg.name;
|
|
135
|
+
dbos_sdk_1.DBOS.logger.info(` ${url} -> ${cname}.${mname}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Decorator - class
|
|
141
|
+
configuration(config) {
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
143
|
+
const er = this;
|
|
144
|
+
function clsdec(ctor) {
|
|
145
|
+
const erInfo = dbos_sdk_1.DBOS.associateClassWithInfo(er, ctor);
|
|
146
|
+
erInfo.config = config;
|
|
147
|
+
}
|
|
148
|
+
return clsdec;
|
|
149
|
+
}
|
|
150
|
+
// Decorators - method
|
|
151
|
+
messageConsumer(config) {
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
153
|
+
const er = this;
|
|
154
|
+
function mtddec(target, propertyKey, inDescriptor) {
|
|
155
|
+
const { regInfo: receiverInfo } = dbos_sdk_1.DBOS.associateFunctionWithInfo(er, inDescriptor.value, {
|
|
156
|
+
classOrInst: target,
|
|
157
|
+
name: propertyKey,
|
|
158
|
+
});
|
|
159
|
+
const mRegistration = receiverInfo;
|
|
160
|
+
mRegistration.config = config;
|
|
161
|
+
return inDescriptor;
|
|
162
|
+
}
|
|
163
|
+
return mtddec;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.SQSReceiver = SQSReceiver;
|
|
167
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqs.test.d.ts","sourceRoot":"","sources":["../sqs.test.ts"],"names":[],"mappings":""}
|
package/dist/sqs.test.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
13
|
+
const index_1 = require("./index");
|
|
14
|
+
const dbos_sdk_1 = require("@dbos-inc/dbos-sdk");
|
|
15
|
+
const sleepms = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
16
|
+
function createSQS() {
|
|
17
|
+
return new client_sqs_1.SQSClient({
|
|
18
|
+
region: process.env['AWS_REGION'] ?? '',
|
|
19
|
+
endpoint: process.env['AWS_ENDPOINT_URL_SQS'],
|
|
20
|
+
credentials: {
|
|
21
|
+
accessKeyId: process.env['AWS_ACCESS_KEY_ID'] ?? '',
|
|
22
|
+
secretAccessKey: process.env['AWS_SECRET_ACCESS_KEY'] ?? '',
|
|
23
|
+
},
|
|
24
|
+
//logger: console,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async function sendMessageInternal(msg) {
|
|
28
|
+
try {
|
|
29
|
+
const smsg = { ...msg, QueueUrl: msg.QueueUrl || process.env['SQS_QUEUE_URL'] };
|
|
30
|
+
return await createSQS().send(new client_sqs_1.SendMessageCommand(smsg));
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
dbos_sdk_1.DBOS.logger.error(e);
|
|
34
|
+
throw e;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const sendMessageStep = dbos_sdk_1.DBOS.registerStep(sendMessageInternal, { name: 'Send SQS Message' });
|
|
38
|
+
const sqsReceiver = new index_1.SQSReceiver({
|
|
39
|
+
client: createSQS,
|
|
40
|
+
});
|
|
41
|
+
class SQSRcv {
|
|
42
|
+
static msgRcvCount = 0;
|
|
43
|
+
static msgValueSum = 0;
|
|
44
|
+
static async recvMessage(msg) {
|
|
45
|
+
const ms = msg.Body;
|
|
46
|
+
const res = JSON.parse(ms);
|
|
47
|
+
SQSRcv.msgRcvCount++;
|
|
48
|
+
SQSRcv.msgValueSum += res.val;
|
|
49
|
+
return Promise.resolve();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
__decorate([
|
|
53
|
+
sqsReceiver.messageConsumer({ queueUrl: process.env['SQS_QUEUE_URL'] }),
|
|
54
|
+
dbos_sdk_1.DBOS.workflow(),
|
|
55
|
+
__metadata("design:type", Function),
|
|
56
|
+
__metadata("design:paramtypes", [Object]),
|
|
57
|
+
__metadata("design:returntype", Promise)
|
|
58
|
+
], SQSRcv, "recvMessage", null);
|
|
59
|
+
describe('sqs-tests', () => {
|
|
60
|
+
let sqsIsAvailable = true;
|
|
61
|
+
beforeAll(() => {
|
|
62
|
+
// Check if SES is available and update app config, skip the test if it's not
|
|
63
|
+
if (!process.env['AWS_REGION'] || !process.env['SQS_QUEUE_URL']) {
|
|
64
|
+
sqsIsAvailable = false;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// This would normally be a global or static or something
|
|
68
|
+
dbos_sdk_1.DBOS.setConfig({ name: 'dbossqstest' });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
beforeEach(async () => {
|
|
72
|
+
if (sqsIsAvailable) {
|
|
73
|
+
dbos_sdk_1.DBOS.registerLifecycleCallback(sqsReceiver);
|
|
74
|
+
await dbos_sdk_1.DBOS.launch();
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
console.log('SQS Test is not configured. To run, set AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and SQS_QUEUE_URL');
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
afterEach(async () => {
|
|
81
|
+
if (sqsIsAvailable) {
|
|
82
|
+
await dbos_sdk_1.DBOS.shutdown();
|
|
83
|
+
}
|
|
84
|
+
}, 10000);
|
|
85
|
+
// This tests receive also; which is already wired up
|
|
86
|
+
test('sqs-send', async () => {
|
|
87
|
+
if (!sqsIsAvailable) {
|
|
88
|
+
console.log('SQS unavailable, skipping SQS tests');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const sv = {
|
|
92
|
+
val: 10,
|
|
93
|
+
};
|
|
94
|
+
const ser = await sendMessageStep({
|
|
95
|
+
MessageBody: JSON.stringify(sv),
|
|
96
|
+
});
|
|
97
|
+
expect(ser.MessageId).toBeDefined();
|
|
98
|
+
// Wait for receipt
|
|
99
|
+
for (let i = 0; i < 100; ++i) {
|
|
100
|
+
if (SQSRcv.msgRcvCount === 1)
|
|
101
|
+
break;
|
|
102
|
+
await sleepms(100);
|
|
103
|
+
}
|
|
104
|
+
expect(SQSRcv.msgRcvCount).toBe(1);
|
|
105
|
+
expect(SQSRcv.msgValueSum).toBe(10);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=sqs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqs.test.js","sourceRoot":"","sources":["../sqs.test.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,oDAAsG;AACtG,mCAAsC;AACtC,iDAA0C;AAE1C,MAAM,OAAO,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAMtE,SAAS,SAAS;IAChB,OAAO,IAAI,sBAAS,CAAC;QACnB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE;QACvC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;QAC7C,WAAW,EAAE;YACX,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,EAAE;YACnD,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,IAAI,EAAE;SAC5D;QACD,kBAAkB;KACnB,CAAC,CAAC;AACL,CAAC;AAQD,KAAK,UAAU,mBAAmB,CAAC,GAAgC;IACjE,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,GAAG,GAAG,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAE,EAAE,CAAC;QACjF,OAAO,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,+BAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,eAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,eAAe,GAAG,eAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC;AAE7F,MAAM,WAAW,GAAG,IAAI,mBAAW,CAAC;IAClC,MAAM,EAAE,SAAS;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM;IACV,MAAM,CAAC,WAAW,GAAW,CAAC,CAAC;IAC/B,MAAM,CAAC,WAAW,GAAW,CAAC,CAAC;IAGlB,AAAb,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,GAAY;QACnC,MAAM,EAAE,GAAG,GAAG,CAAC,IAAK,CAAC;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAa,CAAC;QACvC,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG,CAAC;QAC9B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;;AANY;IAFZ,WAAW,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;IACvE,eAAI,CAAC,QAAQ,EAAE;;;;+BAOf;AAGH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,IAAI,cAAc,GAAG,IAAI,CAAC;IAE1B,SAAS,CAAC,GAAG,EAAE;QACb,6EAA6E;QAC7E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YAChE,cAAc,GAAG,KAAK,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,yDAAyD;YACzD,eAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,IAAI,cAAc,EAAE,CAAC;YACnB,eAAI,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAC;YAC5C,MAAM,eAAI,CAAC,MAAM,EAAE,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CACT,kHAAkH,CACnH,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,eAAI,CAAC,QAAQ,EAAE,CAAC;QACxB,CAAC;IACH,CAAC,EAAE,KAAK,CAAC,CAAC;IAEV,qDAAqD;IACrD,IAAI,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;QAC1B,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;YACnD,OAAO;QACT,CAAC;QACD,MAAM,EAAE,GAAa;YACnB,GAAG,EAAE,EAAE;SACR,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC;YAChC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;SAChC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAEpC,mBAAmB;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,WAAW,KAAK,CAAC;gBAAE,MAAM;YACpC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|