@goatlab/tasks-adapter-gcp 0.3.4 → 0.4.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/dist/CloudTaskConnector.d.ts +118 -9
- package/dist/CloudTaskConnector.js +147 -9
- package/dist/CloudTaskConnector.js.map +1 -1
- package/dist/MockCloudTaskConnector.d.ts +49 -0
- package/dist/MockCloudTaskConnector.js +146 -0
- package/dist/MockCloudTaskConnector.js.map +1 -0
- package/dist/benchmark.d.ts +17 -0
- package/dist/benchmark.js +260 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/cloudtask.spec.js +144 -52
- package/dist/cloudtask.spec.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -1,20 +1,129 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Primitive } from '@goatlab/js-utils';
|
|
3
|
-
import type { TaskConnector, TaskStatus } from '@goatlab/tasks-core';
|
|
3
|
+
import type { TaskConnector, TaskStatus, TenantCredentials } from '@goatlab/tasks-core';
|
|
4
4
|
import type { BackoffSettings } from 'google-gax/build/src/gax';
|
|
5
|
+
import { GCPServiceAccount } from './CloudTaskConnector.types.js';
|
|
5
6
|
export type ITask = any;
|
|
6
7
|
export type { BackoffSettings };
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for CloudTaskConnector
|
|
10
|
+
*/
|
|
11
|
+
export interface CloudTaskConnectorConfig {
|
|
12
|
+
/**
|
|
13
|
+
* GCP service account credentials for authentication.
|
|
14
|
+
*/
|
|
15
|
+
gcpServiceAccount?: GCPServiceAccount;
|
|
16
|
+
/**
|
|
17
|
+
* GCP region/location for Cloud Tasks queues.
|
|
18
|
+
* Default: 'europe-west1'
|
|
19
|
+
*/
|
|
20
|
+
location?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Encryption key for task body encryption.
|
|
23
|
+
*/
|
|
24
|
+
encryptionKey?: string;
|
|
25
|
+
/**
|
|
26
|
+
* GCP project ID.
|
|
27
|
+
*/
|
|
28
|
+
gcpProject: string;
|
|
29
|
+
/**
|
|
30
|
+
* Tenant ID for multi-tenant isolation.
|
|
31
|
+
* When set, this tenant ID is used as a prefix for task names.
|
|
32
|
+
*
|
|
33
|
+
* Task naming pattern: {tenantId}-{taskName}
|
|
34
|
+
* Example: "acme-corp-my-task" instead of "my-task"
|
|
35
|
+
*
|
|
36
|
+
* This ensures each tenant's tasks are uniquely identified,
|
|
37
|
+
* providing isolation at the task level while sharing the same queue.
|
|
38
|
+
*/
|
|
39
|
+
tenantId?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Enable in-memory payload caching for testing.
|
|
42
|
+
* GCP Cloud Tasks removes completed tasks immediately, which means
|
|
43
|
+
* getStatus() cannot retrieve the payload after completion.
|
|
44
|
+
*
|
|
45
|
+
* When enabled, payloads are cached in memory when queueing
|
|
46
|
+
* and returned from getStatus() even after the task is removed.
|
|
47
|
+
*
|
|
48
|
+
* WARNING: Only enable for testing. In production, this will cause
|
|
49
|
+
* memory leaks as payloads accumulate.
|
|
50
|
+
*
|
|
51
|
+
* Default: false
|
|
52
|
+
*/
|
|
53
|
+
enablePayloadCache?: boolean;
|
|
54
|
+
}
|
|
7
55
|
export declare class CloudTaskConnector implements TaskConnector<object> {
|
|
8
56
|
private gcpServiceAccount;
|
|
9
57
|
private location;
|
|
10
58
|
private encryptionKey;
|
|
11
59
|
private gcpProject;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
60
|
+
private readonly _tenantId?;
|
|
61
|
+
private readonly config;
|
|
62
|
+
private readonly enablePayloadCache;
|
|
63
|
+
/**
|
|
64
|
+
* Cache for task payloads (only used when enablePayloadCache is true).
|
|
65
|
+
* GCP Cloud Tasks removes completed tasks immediately, so we cache the payload
|
|
66
|
+
* to return it when getStatus is called after completion.
|
|
67
|
+
* Key: task name (full path), Value: { payload, createdAt }
|
|
68
|
+
*/
|
|
69
|
+
private static payloadCache;
|
|
70
|
+
/**
|
|
71
|
+
* How long to keep payloads in cache (1 hour)
|
|
72
|
+
*/
|
|
73
|
+
private static readonly CACHE_TTL_MS;
|
|
74
|
+
/**
|
|
75
|
+
* The tenant ID this connector is scoped to.
|
|
76
|
+
* When set, task names are prefixed with this tenant ID.
|
|
77
|
+
*/
|
|
78
|
+
get tenantId(): string | undefined;
|
|
79
|
+
constructor(config: CloudTaskConnectorConfig);
|
|
80
|
+
/**
|
|
81
|
+
* Cleans up expired entries from the payload cache.
|
|
82
|
+
*/
|
|
83
|
+
private cleanupCache;
|
|
84
|
+
/**
|
|
85
|
+
* Caches a task's payload for later retrieval.
|
|
86
|
+
* Only caches if enablePayloadCache is true.
|
|
87
|
+
*/
|
|
88
|
+
private cachePayload;
|
|
89
|
+
/**
|
|
90
|
+
* Gets a cached payload if available.
|
|
91
|
+
* Only returns cached data if enablePayloadCache is true.
|
|
92
|
+
*/
|
|
93
|
+
private getCachedPayload;
|
|
94
|
+
/**
|
|
95
|
+
* Creates a new CloudTaskConnector instance scoped to a specific tenant.
|
|
96
|
+
* Uses tenant ID as a prefix for queue names for isolation.
|
|
97
|
+
*
|
|
98
|
+
* @param tenantId - The tenant identifier for isolation (used as queue name prefix)
|
|
99
|
+
* @param credentials - Optional GCP credentials for the tenant (uses parent's if not provided)
|
|
100
|
+
* @returns A new CloudTaskConnector instance scoped to the tenant
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* const baseConnector = new CloudTaskConnector({ gcpProject: 'my-project' })
|
|
105
|
+
*
|
|
106
|
+
* // Create tenant-scoped connector
|
|
107
|
+
* const tenantConnector = baseConnector.forTenant('acme-corp')
|
|
108
|
+
* // Queue names: acme-corp-default, acme-corp-email-queue, etc.
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
forTenant(tenantId: string, _credentials?: TenantCredentials): CloudTaskConnector;
|
|
112
|
+
/**
|
|
113
|
+
* Sanitizes a string for use in GCP Cloud Tasks names.
|
|
114
|
+
* GCP names only allow letters, numbers, and hyphens.
|
|
115
|
+
* @param value - The value to sanitize
|
|
116
|
+
* @returns Sanitized value safe for GCP names
|
|
117
|
+
*/
|
|
118
|
+
private sanitizeForGcp;
|
|
119
|
+
/**
|
|
120
|
+
* Gets the task name with tenant prefix applied if tenant is set.
|
|
121
|
+
* Task-level isolation: all tenants share the same queue, but task names are prefixed.
|
|
122
|
+
* This avoids the overhead of creating separate queues per tenant.
|
|
123
|
+
* @param taskName - The base task name
|
|
124
|
+
* @returns The full task name with tenant prefix if applicable
|
|
125
|
+
*/
|
|
126
|
+
private getTaskName;
|
|
18
127
|
private getCloudTasksClient;
|
|
19
128
|
/**
|
|
20
129
|
* Adds a task to the Cloud Tasks queue.
|
|
@@ -25,7 +134,7 @@ export declare class CloudTaskConnector implements TaskConnector<object> {
|
|
|
25
134
|
queueName: string;
|
|
26
135
|
backoffSettings: any;
|
|
27
136
|
baseUrl?: string;
|
|
28
|
-
}): Promise<import("@google-cloud/tasks/build/protos/protos").google.cloud.tasks.v2.ITask>;
|
|
137
|
+
}): Promise<import("@google-cloud/tasks/build/protos/protos.js").google.cloud.tasks.v2.ITask>;
|
|
29
138
|
/**
|
|
30
139
|
* Lists all failed tasks in the specified queue.
|
|
31
140
|
* It filters tasks that have been dispatched more than twice,
|
|
@@ -34,7 +143,7 @@ export declare class CloudTaskConnector implements TaskConnector<object> {
|
|
|
34
143
|
* @param queueName - Name of the queue to list failed tasks from.
|
|
35
144
|
* @returns An array of failed tasks.
|
|
36
145
|
*/
|
|
37
|
-
listFailedTasks(queueName?: string): Promise<import("@google-cloud/tasks/build/protos/protos").google.cloud.tasks.v2.ITask[]>;
|
|
146
|
+
listFailedTasks(queueName?: string): Promise<import("@google-cloud/tasks/build/protos/protos.js").google.cloud.tasks.v2.ITask[]>;
|
|
38
147
|
/**
|
|
39
148
|
* Decrypts the body of a task.
|
|
40
149
|
* This service encrypts the body of the task before sending it,
|
|
@@ -28,11 +28,138 @@ class CloudTaskConnector {
|
|
|
28
28
|
location;
|
|
29
29
|
encryptionKey;
|
|
30
30
|
gcpProject;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
_tenantId;
|
|
32
|
+
config;
|
|
33
|
+
enablePayloadCache;
|
|
34
|
+
/**
|
|
35
|
+
* Cache for task payloads (only used when enablePayloadCache is true).
|
|
36
|
+
* GCP Cloud Tasks removes completed tasks immediately, so we cache the payload
|
|
37
|
+
* to return it when getStatus is called after completion.
|
|
38
|
+
* Key: task name (full path), Value: { payload, createdAt }
|
|
39
|
+
*/
|
|
40
|
+
static payloadCache = new Map();
|
|
41
|
+
/**
|
|
42
|
+
* How long to keep payloads in cache (1 hour)
|
|
43
|
+
*/
|
|
44
|
+
static CACHE_TTL_MS = 60 * 60 * 1000;
|
|
45
|
+
/**
|
|
46
|
+
* The tenant ID this connector is scoped to.
|
|
47
|
+
* When set, task names are prefixed with this tenant ID.
|
|
48
|
+
*/
|
|
49
|
+
get tenantId() {
|
|
50
|
+
return this._tenantId;
|
|
51
|
+
}
|
|
52
|
+
constructor(config) {
|
|
53
|
+
this.config = config;
|
|
54
|
+
this.gcpServiceAccount = (config.gcpServiceAccount ||
|
|
55
|
+
'');
|
|
56
|
+
this.location = config.location || 'europe-west1';
|
|
57
|
+
this.encryptionKey = config.encryptionKey || '';
|
|
58
|
+
this.gcpProject = config.gcpProject || '';
|
|
59
|
+
this._tenantId = config.tenantId;
|
|
60
|
+
this.enablePayloadCache = config.enablePayloadCache ?? false;
|
|
61
|
+
// Periodically clean up old cache entries (only if caching is enabled)
|
|
62
|
+
if (this.enablePayloadCache) {
|
|
63
|
+
this.cleanupCache();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Cleans up expired entries from the payload cache.
|
|
68
|
+
*/
|
|
69
|
+
cleanupCache() {
|
|
70
|
+
if (!this.enablePayloadCache) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
for (const [key, value] of CloudTaskConnector.payloadCache) {
|
|
75
|
+
if (now - value.createdAt > CloudTaskConnector.CACHE_TTL_MS) {
|
|
76
|
+
CloudTaskConnector.payloadCache.delete(key);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Caches a task's payload for later retrieval.
|
|
82
|
+
* Only caches if enablePayloadCache is true.
|
|
83
|
+
*/
|
|
84
|
+
cachePayload(taskName, payload) {
|
|
85
|
+
if (!this.enablePayloadCache) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
CloudTaskConnector.payloadCache.set(taskName, {
|
|
89
|
+
payload,
|
|
90
|
+
createdAt: Date.now()
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Gets a cached payload if available.
|
|
95
|
+
* Only returns cached data if enablePayloadCache is true.
|
|
96
|
+
*/
|
|
97
|
+
getCachedPayload(taskName) {
|
|
98
|
+
if (!this.enablePayloadCache) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
const cached = CloudTaskConnector.payloadCache.get(taskName);
|
|
102
|
+
if (cached) {
|
|
103
|
+
// Check if expired
|
|
104
|
+
if (Date.now() - cached.createdAt > CloudTaskConnector.CACHE_TTL_MS) {
|
|
105
|
+
CloudTaskConnector.payloadCache.delete(taskName);
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
return cached.payload;
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Creates a new CloudTaskConnector instance scoped to a specific tenant.
|
|
114
|
+
* Uses tenant ID as a prefix for queue names for isolation.
|
|
115
|
+
*
|
|
116
|
+
* @param tenantId - The tenant identifier for isolation (used as queue name prefix)
|
|
117
|
+
* @param credentials - Optional GCP credentials for the tenant (uses parent's if not provided)
|
|
118
|
+
* @returns A new CloudTaskConnector instance scoped to the tenant
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const baseConnector = new CloudTaskConnector({ gcpProject: 'my-project' })
|
|
123
|
+
*
|
|
124
|
+
* // Create tenant-scoped connector
|
|
125
|
+
* const tenantConnector = baseConnector.forTenant('acme-corp')
|
|
126
|
+
* // Queue names: acme-corp-default, acme-corp-email-queue, etc.
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
forTenant(tenantId, _credentials) {
|
|
130
|
+
return new CloudTaskConnector({
|
|
131
|
+
...this.config,
|
|
132
|
+
tenantId
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Sanitizes a string for use in GCP Cloud Tasks names.
|
|
137
|
+
* GCP names only allow letters, numbers, and hyphens.
|
|
138
|
+
* @param value - The value to sanitize
|
|
139
|
+
* @returns Sanitized value safe for GCP names
|
|
140
|
+
*/
|
|
141
|
+
sanitizeForGcp(value) {
|
|
142
|
+
// Replace underscores and other invalid chars with hyphens
|
|
143
|
+
// Remove any consecutive hyphens and trim hyphens from ends
|
|
144
|
+
return value
|
|
145
|
+
.replace(/[^a-zA-Z0-9-]/g, '-')
|
|
146
|
+
.replace(/-+/g, '-')
|
|
147
|
+
.replace(/^-|-$/g, '');
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Gets the task name with tenant prefix applied if tenant is set.
|
|
151
|
+
* Task-level isolation: all tenants share the same queue, but task names are prefixed.
|
|
152
|
+
* This avoids the overhead of creating separate queues per tenant.
|
|
153
|
+
* @param taskName - The base task name
|
|
154
|
+
* @returns The full task name with tenant prefix if applicable
|
|
155
|
+
*/
|
|
156
|
+
getTaskName(taskName) {
|
|
157
|
+
const sanitizedTask = this.sanitizeForGcp(taskName);
|
|
158
|
+
if (this._tenantId) {
|
|
159
|
+
const sanitizedTenant = this.sanitizeForGcp(this._tenantId);
|
|
160
|
+
return `${sanitizedTenant}-${sanitizedTask}`;
|
|
161
|
+
}
|
|
162
|
+
return sanitizedTask;
|
|
36
163
|
}
|
|
37
164
|
async getCloudTasksClient() {
|
|
38
165
|
const cloudTasks = await Promise.resolve().then(() => require('@google-cloud/tasks'));
|
|
@@ -54,6 +181,7 @@ class CloudTaskConnector {
|
|
|
54
181
|
const parsedURL = new URL(url, baseUrl);
|
|
55
182
|
(0, js_utils_1.assert)(parsedURL, 'Task URL is invalid');
|
|
56
183
|
const client = await this.getCloudTasksClient();
|
|
184
|
+
// Use queue name directly - tenant isolation is at task name level, not queue level
|
|
57
185
|
const parent = client.queuePath(this.gcpProject, this.location, queueName);
|
|
58
186
|
// Build the task object in one go to avoid multiple spreads
|
|
59
187
|
const finalTask = {
|
|
@@ -116,6 +244,7 @@ class CloudTaskConnector {
|
|
|
116
244
|
*/
|
|
117
245
|
async listFailedTasks(queueName = 'default') {
|
|
118
246
|
const client = await this.getCloudTasksClient();
|
|
247
|
+
// Use queue name directly - tenant isolation is at task name level
|
|
119
248
|
const parent = client.queuePath(this.gcpProject, this.location, queueName);
|
|
120
249
|
// We have to be careful with the response, as it can be large.
|
|
121
250
|
const [tasks] = await client.listTasks({ parent, responseView: 'FULL' });
|
|
@@ -167,6 +296,8 @@ class CloudTaskConnector {
|
|
|
167
296
|
if (error?.message.includes('The task no longer exists')) {
|
|
168
297
|
// Extract task name once
|
|
169
298
|
const taskName = name?.split('/').pop() || '';
|
|
299
|
+
// Use cached payload if available (GCP removes completed tasks immediately)
|
|
300
|
+
const cachedPayload = this.getCachedPayload(name) || {};
|
|
170
301
|
return {
|
|
171
302
|
id: name,
|
|
172
303
|
name: taskName,
|
|
@@ -176,7 +307,7 @@ class CloudTaskConnector {
|
|
|
176
307
|
created: new Date().toISOString(),
|
|
177
308
|
nextRun: null,
|
|
178
309
|
nextRunMinutes: null,
|
|
179
|
-
payload:
|
|
310
|
+
payload: cachedPayload
|
|
180
311
|
};
|
|
181
312
|
}
|
|
182
313
|
const task = resp[0];
|
|
@@ -216,9 +347,13 @@ class CloudTaskConnector {
|
|
|
216
347
|
* @param params.taskBody - Body of the task.
|
|
217
348
|
*/
|
|
218
349
|
async queue(params) {
|
|
350
|
+
// Apply tenant prefix to task name for multi-tenant isolation
|
|
351
|
+
// All tenants share the same queue, but task names are prefixed
|
|
352
|
+
const baseTaskName = `${params.uniqueTaskName}-${js_utils_1.Ids.nanoId(5)}`;
|
|
353
|
+
const taskName = this.getTaskName(baseTaskName);
|
|
219
354
|
const task = await this.addTask({
|
|
220
355
|
task: {
|
|
221
|
-
name:
|
|
356
|
+
name: taskName,
|
|
222
357
|
httpRequest: {
|
|
223
358
|
url: params.postUrl,
|
|
224
359
|
body: JSON.stringify(params.taskBody)
|
|
@@ -227,12 +362,15 @@ class CloudTaskConnector {
|
|
|
227
362
|
queueName: params.queueName || 'default',
|
|
228
363
|
backoffSettings: defaultBackoffSettings
|
|
229
364
|
});
|
|
365
|
+
// Cache the payload so we can return it even after GCP removes the completed task
|
|
366
|
+
if (task.name) {
|
|
367
|
+
this.cachePayload(task.name, params.taskBody);
|
|
368
|
+
}
|
|
230
369
|
const creation = Number(task.createTime?.seconds || 0) || 0;
|
|
231
370
|
const scheduled = Number(task.scheduleTime?.seconds || 0) || 0;
|
|
232
|
-
const taskName = task.name.split('/').pop() || '';
|
|
233
371
|
return {
|
|
234
372
|
id: task.name,
|
|
235
|
-
name: taskName,
|
|
373
|
+
name: params.taskName,
|
|
236
374
|
output: '',
|
|
237
375
|
attempts: 0,
|
|
238
376
|
status: 'QUEUED',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudTaskConnector.js","sourceRoot":"","sources":["../src/CloudTaskConnector.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"CloudTaskConnector.js","sourceRoot":"","sources":["../src/CloudTaskConnector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MockCloudTaskConnector - In-memory mock for testing
|
|
3
|
+
*
|
|
4
|
+
* This connector simulates GCP Cloud Tasks behavior locally for testing purposes.
|
|
5
|
+
* It stores tasks in memory and executes them via a simulated worker,
|
|
6
|
+
* allowing us to run the same test suite as BullMQ and Hatchet adapters.
|
|
7
|
+
*/
|
|
8
|
+
import type { ShouldQueue, TaskConnector, TaskStatus } from '@goatlab/tasks-core';
|
|
9
|
+
export declare class MockCloudTaskConnector implements TaskConnector<object> {
|
|
10
|
+
private tasks;
|
|
11
|
+
private taskHandlers;
|
|
12
|
+
private isProcessing;
|
|
13
|
+
private processInterval;
|
|
14
|
+
/**
|
|
15
|
+
* Registers task handlers (similar to BullMQ/Hatchet startWorker).
|
|
16
|
+
* This allows the mock to execute tasks when they are queued.
|
|
17
|
+
*/
|
|
18
|
+
startWorker({ tasks }: {
|
|
19
|
+
workerName?: string;
|
|
20
|
+
tasks: ShouldQueue[];
|
|
21
|
+
}): Promise<() => Promise<void>>;
|
|
22
|
+
/**
|
|
23
|
+
* Processes queued tasks by executing their handlers.
|
|
24
|
+
* Simulates GCP Cloud Tasks calling HTTP endpoints.
|
|
25
|
+
*/
|
|
26
|
+
private processTasks;
|
|
27
|
+
/**
|
|
28
|
+
* Gets the status of a task by its ID.
|
|
29
|
+
*/
|
|
30
|
+
getStatus(id: string): Promise<TaskStatus>;
|
|
31
|
+
/**
|
|
32
|
+
* Queues a task to be run.
|
|
33
|
+
*/
|
|
34
|
+
queue(params: {
|
|
35
|
+
uniqueTaskName: string;
|
|
36
|
+
taskName: string;
|
|
37
|
+
postUrl: string;
|
|
38
|
+
taskBody: object;
|
|
39
|
+
handle: () => Promise<any>;
|
|
40
|
+
}): Promise<Omit<TaskStatus, 'payload'>>;
|
|
41
|
+
/**
|
|
42
|
+
* Clears all stored tasks.
|
|
43
|
+
*/
|
|
44
|
+
clear(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Closes the connector and stops processing.
|
|
47
|
+
*/
|
|
48
|
+
close(): Promise<void>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MockCloudTaskConnector - In-memory mock for testing
|
|
4
|
+
*
|
|
5
|
+
* This connector simulates GCP Cloud Tasks behavior locally for testing purposes.
|
|
6
|
+
* It stores tasks in memory and executes them via a simulated worker,
|
|
7
|
+
* allowing us to run the same test suite as BullMQ and Hatchet adapters.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.MockCloudTaskConnector = void 0;
|
|
11
|
+
const js_utils_1 = require("@goatlab/js-utils");
|
|
12
|
+
class MockCloudTaskConnector {
|
|
13
|
+
tasks = new Map();
|
|
14
|
+
taskHandlers = new Map();
|
|
15
|
+
isProcessing = false;
|
|
16
|
+
processInterval = null;
|
|
17
|
+
/**
|
|
18
|
+
* Registers task handlers (similar to BullMQ/Hatchet startWorker).
|
|
19
|
+
* This allows the mock to execute tasks when they are queued.
|
|
20
|
+
*/
|
|
21
|
+
async startWorker({ tasks }) {
|
|
22
|
+
for (const task of tasks) {
|
|
23
|
+
this.taskHandlers.set(task.taskName, task);
|
|
24
|
+
}
|
|
25
|
+
// Start processing tasks
|
|
26
|
+
this.isProcessing = true;
|
|
27
|
+
this.processInterval = setInterval(() => this.processTasks(), 50);
|
|
28
|
+
return async () => {
|
|
29
|
+
this.isProcessing = false;
|
|
30
|
+
if (this.processInterval) {
|
|
31
|
+
clearInterval(this.processInterval);
|
|
32
|
+
this.processInterval = null;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Processes queued tasks by executing their handlers.
|
|
38
|
+
* Simulates GCP Cloud Tasks calling HTTP endpoints.
|
|
39
|
+
*/
|
|
40
|
+
async processTasks() {
|
|
41
|
+
if (!this.isProcessing) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
for (const [_id, task] of this.tasks.entries()) {
|
|
45
|
+
if (task.status === 'QUEUED') {
|
|
46
|
+
// Mark as running
|
|
47
|
+
task.status = 'RUNNING';
|
|
48
|
+
task.attempts++;
|
|
49
|
+
const handler = this.taskHandlers.get(task.name);
|
|
50
|
+
if (handler) {
|
|
51
|
+
try {
|
|
52
|
+
const result = await handler.handle(task.payload);
|
|
53
|
+
task.status = 'COMPLETED';
|
|
54
|
+
task.output = result ? JSON.stringify(result) : '';
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
task.status = 'FAILED';
|
|
58
|
+
task.output = error?.message || 'Unknown error';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// No handler registered - mark as completed (simulates successful HTTP call)
|
|
63
|
+
task.status = 'COMPLETED';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Gets the status of a task by its ID.
|
|
70
|
+
*/
|
|
71
|
+
async getStatus(id) {
|
|
72
|
+
const task = this.tasks.get(id);
|
|
73
|
+
if (!task) {
|
|
74
|
+
return {
|
|
75
|
+
id,
|
|
76
|
+
name: '',
|
|
77
|
+
status: 'COMPLETED',
|
|
78
|
+
output: 'Task not found',
|
|
79
|
+
attempts: 0,
|
|
80
|
+
created: new Date().toISOString(),
|
|
81
|
+
nextRun: null,
|
|
82
|
+
nextRunMinutes: null,
|
|
83
|
+
payload: {}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
id: task.id,
|
|
88
|
+
name: task.name,
|
|
89
|
+
status: task.status,
|
|
90
|
+
output: task.output,
|
|
91
|
+
attempts: task.attempts,
|
|
92
|
+
created: task.created,
|
|
93
|
+
nextRun: null,
|
|
94
|
+
nextRunMinutes: null,
|
|
95
|
+
payload: task.payload
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Queues a task to be run.
|
|
100
|
+
*/
|
|
101
|
+
async queue(params) {
|
|
102
|
+
const id = `mock-task-${params.uniqueTaskName}_${js_utils_1.Ids.nanoId(5)}`;
|
|
103
|
+
const now = new Date().toISOString();
|
|
104
|
+
const storedTask = {
|
|
105
|
+
id,
|
|
106
|
+
name: params.taskName,
|
|
107
|
+
payload: params.taskBody,
|
|
108
|
+
status: 'QUEUED',
|
|
109
|
+
attempts: 0,
|
|
110
|
+
created: now,
|
|
111
|
+
output: '',
|
|
112
|
+
handle: params.handle
|
|
113
|
+
};
|
|
114
|
+
this.tasks.set(id, storedTask);
|
|
115
|
+
return {
|
|
116
|
+
id,
|
|
117
|
+
name: params.taskName,
|
|
118
|
+
output: '',
|
|
119
|
+
attempts: 0,
|
|
120
|
+
status: 'QUEUED',
|
|
121
|
+
created: now,
|
|
122
|
+
nextRun: null,
|
|
123
|
+
nextRunMinutes: null
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Clears all stored tasks.
|
|
128
|
+
*/
|
|
129
|
+
clear() {
|
|
130
|
+
this.tasks.clear();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Closes the connector and stops processing.
|
|
134
|
+
*/
|
|
135
|
+
async close() {
|
|
136
|
+
this.isProcessing = false;
|
|
137
|
+
if (this.processInterval) {
|
|
138
|
+
clearInterval(this.processInterval);
|
|
139
|
+
this.processInterval = null;
|
|
140
|
+
}
|
|
141
|
+
this.tasks.clear();
|
|
142
|
+
this.taskHandlers.clear();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.MockCloudTaskConnector = MockCloudTaskConnector;
|
|
146
|
+
//# sourceMappingURL=MockCloudTaskConnector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockCloudTaskConnector.js","sourceRoot":"","sources":["../src/MockCloudTaskConnector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GCP Cloud Tasks Benchmark Script
|
|
3
|
+
*
|
|
4
|
+
* Run with: npx tsx src/benchmark.ts [mode]
|
|
5
|
+
*
|
|
6
|
+
* Modes:
|
|
7
|
+
* (default) - Run queue throughput benchmark
|
|
8
|
+
* payload - Compare different payload sizes
|
|
9
|
+
* batch - Compare different batch sizes
|
|
10
|
+
*
|
|
11
|
+
* Requires FIREBASE_SERVICE_ACCOUNT environment variable.
|
|
12
|
+
*
|
|
13
|
+
* Note: GCP Cloud Tasks is HTTP callback based, so we can only measure
|
|
14
|
+
* queue throughput (enqueue rate). E2E and latency tests would require
|
|
15
|
+
* a real HTTP endpoint to receive callbacks.
|
|
16
|
+
*/
|
|
17
|
+
import 'dotenv/config';
|