@causa/runtime-google 0.38.0 → 0.39.1
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/transaction/spanner-outbox/event.d.ts +2 -17
- package/dist/transaction/spanner-outbox/event.js +2 -21
- package/dist/transaction/spanner-outbox/module.d.ts +2 -2
- package/dist/transaction/spanner-outbox/module.js +0 -2
- package/dist/transaction/spanner-outbox/runner.d.ts +2 -3
- package/dist/transaction/spanner-outbox/sender.d.ts +0 -9
- package/dist/transaction/spanner-outbox/sender.js +3 -20
- package/package.json +12 -12
|
@@ -11,22 +11,11 @@ import type { EventAttributes, OutboxEvent } from '@causa/runtime';
|
|
|
11
11
|
* data BYTES(MAX) NOT NULL,
|
|
12
12
|
* attributes JSON NOT NULL,
|
|
13
13
|
* leaseExpiration TIMESTAMP,
|
|
14
|
-
* publishedAt TIMESTAMP,
|
|
15
14
|
* -- 20 is the number of shards.
|
|
16
15
|
* shard INT64 AS (MOD(ABS(FARM_FINGERPRINT(id)), 20)),
|
|
17
|
-
* ) PRIMARY KEY (id)
|
|
18
|
-
*
|
|
19
|
-
* CREATE INDEX OutboxEventsByShardAndLeaseExpiration ON OutboxEvent(shard, leaseExpiration) STORING (publishedAt);
|
|
16
|
+
* ) PRIMARY KEY (id);
|
|
17
|
+
* CREATE INDEX OutboxEventsByShardAndLeaseExpiration ON OutboxEvent(shard, leaseExpiration)
|
|
20
18
|
* ```
|
|
21
|
-
*
|
|
22
|
-
* Compared to the {@link OutboxEvent} interface, this requires a `publishedAt` column to be defined, on which the row
|
|
23
|
-
* deletion policy should be set. This allows updating published events rather than deleting them directly.
|
|
24
|
-
* Updating published events allows setting the `leaseExpiration` column to a distant date, such that those events are
|
|
25
|
-
* not scanned when fetching events to publish.
|
|
26
|
-
* Because Spanner allows for version retention, recently deleted rows are still scanned (even as part of an efficient
|
|
27
|
-
* index scan). This can affect performances if the rows are not updated before being deleted, because the
|
|
28
|
-
* `leaseExpiration` date of published events would end up back in the scanned range - in the past (although rows are
|
|
29
|
-
* deleted and not returned).
|
|
30
19
|
*/
|
|
31
20
|
export declare class SpannerOutboxEvent implements OutboxEvent {
|
|
32
21
|
constructor(init: SpannerOutboxEvent);
|
|
@@ -35,8 +24,4 @@ export declare class SpannerOutboxEvent implements OutboxEvent {
|
|
|
35
24
|
readonly data: Buffer;
|
|
36
25
|
readonly attributes: EventAttributes;
|
|
37
26
|
readonly leaseExpiration: Date | null;
|
|
38
|
-
/**
|
|
39
|
-
* The date at which the event was successfully published.
|
|
40
|
-
*/
|
|
41
|
-
readonly publishedAt: Date | null;
|
|
42
27
|
}
|
|
@@ -20,22 +20,11 @@ import { SpannerColumn, SpannerTable } from '../../spanner/index.js';
|
|
|
20
20
|
* data BYTES(MAX) NOT NULL,
|
|
21
21
|
* attributes JSON NOT NULL,
|
|
22
22
|
* leaseExpiration TIMESTAMP,
|
|
23
|
-
* publishedAt TIMESTAMP,
|
|
24
23
|
* -- 20 is the number of shards.
|
|
25
24
|
* shard INT64 AS (MOD(ABS(FARM_FINGERPRINT(id)), 20)),
|
|
26
|
-
* ) PRIMARY KEY (id)
|
|
27
|
-
*
|
|
28
|
-
* CREATE INDEX OutboxEventsByShardAndLeaseExpiration ON OutboxEvent(shard, leaseExpiration) STORING (publishedAt);
|
|
25
|
+
* ) PRIMARY KEY (id);
|
|
26
|
+
* CREATE INDEX OutboxEventsByShardAndLeaseExpiration ON OutboxEvent(shard, leaseExpiration)
|
|
29
27
|
* ```
|
|
30
|
-
*
|
|
31
|
-
* Compared to the {@link OutboxEvent} interface, this requires a `publishedAt` column to be defined, on which the row
|
|
32
|
-
* deletion policy should be set. This allows updating published events rather than deleting them directly.
|
|
33
|
-
* Updating published events allows setting the `leaseExpiration` column to a distant date, such that those events are
|
|
34
|
-
* not scanned when fetching events to publish.
|
|
35
|
-
* Because Spanner allows for version retention, recently deleted rows are still scanned (even as part of an efficient
|
|
36
|
-
* index scan). This can affect performances if the rows are not updated before being deleted, because the
|
|
37
|
-
* `leaseExpiration` date of published events would end up back in the scanned range - in the past (although rows are
|
|
38
|
-
* deleted and not returned).
|
|
39
28
|
*/
|
|
40
29
|
let SpannerOutboxEvent = class SpannerOutboxEvent {
|
|
41
30
|
constructor(init) {
|
|
@@ -46,10 +35,6 @@ let SpannerOutboxEvent = class SpannerOutboxEvent {
|
|
|
46
35
|
data;
|
|
47
36
|
attributes;
|
|
48
37
|
leaseExpiration;
|
|
49
|
-
/**
|
|
50
|
-
* The date at which the event was successfully published.
|
|
51
|
-
*/
|
|
52
|
-
publishedAt;
|
|
53
38
|
};
|
|
54
39
|
__decorate([
|
|
55
40
|
SpannerColumn(),
|
|
@@ -71,10 +56,6 @@ __decorate([
|
|
|
71
56
|
SpannerColumn(),
|
|
72
57
|
__metadata("design:type", Object)
|
|
73
58
|
], SpannerOutboxEvent.prototype, "leaseExpiration", void 0);
|
|
74
|
-
__decorate([
|
|
75
|
-
SpannerColumn(),
|
|
76
|
-
__metadata("design:type", Object)
|
|
77
|
-
], SpannerOutboxEvent.prototype, "publishedAt", void 0);
|
|
78
59
|
SpannerOutboxEvent = __decorate([
|
|
79
60
|
SpannerTable({ name: 'OutboxEvent', primaryKey: ['id'] }),
|
|
80
61
|
__metadata("design:paramtypes", [SpannerOutboxEvent])
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { OutboxEvent } from '@causa/runtime';
|
|
1
2
|
import type { DynamicModule, Type } from '@nestjs/common';
|
|
2
|
-
import { SpannerOutboxEvent } from './event.js';
|
|
3
3
|
import { type SpannerOutboxSenderOptions } from './sender.js';
|
|
4
4
|
/**
|
|
5
5
|
* Options for the {@link SpannerOutboxTransactionModule}.
|
|
@@ -10,7 +10,7 @@ export type SpannerOutboxTransactionModuleOptions = SpannerOutboxSenderOptions &
|
|
|
10
10
|
* This should be a valid class decorated with `@SpannerTable`.
|
|
11
11
|
* Defaults to {@link SpannerOutboxEvent}.
|
|
12
12
|
*/
|
|
13
|
-
outboxEventType?: Type<
|
|
13
|
+
outboxEventType?: Type<OutboxEvent>;
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
16
|
* The module providing the {@link SpannerOutboxTransactionRunner}.
|
|
@@ -29,7 +29,6 @@ function parseSenderOptions(defaultOptions, customOptions, config) {
|
|
|
29
29
|
const pollingInterval = validateIntOrUndefined('SPANNER_OUTBOX_POLLING_INTERVAL');
|
|
30
30
|
const idColumn = config.get('SPANNER_OUTBOX_ID_COLUMN');
|
|
31
31
|
const leaseExpirationColumn = config.get('SPANNER_OUTBOX_LEASE_EXPIRATION_COLUMN');
|
|
32
|
-
const publishedAtColumn = config.get('SPANNER_OUTBOX_PUBLISHED_AT_COLUMN');
|
|
33
32
|
const index = config.get('SPANNER_OUTBOX_INDEX');
|
|
34
33
|
const shardingColumn = config.get('SPANNER_OUTBOX_SHARDING_COLUMN');
|
|
35
34
|
const shardingCount = validateIntOrUndefined('SPANNER_OUTBOX_SHARDING_COUNT');
|
|
@@ -42,7 +41,6 @@ function parseSenderOptions(defaultOptions, customOptions, config) {
|
|
|
42
41
|
pollingInterval,
|
|
43
42
|
idColumn,
|
|
44
43
|
leaseExpirationColumn,
|
|
45
|
-
publishedAtColumn,
|
|
46
44
|
index,
|
|
47
45
|
sharding,
|
|
48
46
|
leaseDuration,
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { OutboxTransactionRunner, type OutboxEventTransaction } from '@causa/runtime';
|
|
1
|
+
import { OutboxTransactionRunner, type OutboxEvent, type OutboxEventTransaction } from '@causa/runtime';
|
|
2
2
|
import { Logger } from '@causa/runtime/nestjs';
|
|
3
3
|
import type { Type } from '@nestjs/common';
|
|
4
4
|
import { SpannerEntityManager } from '../../spanner/index.js';
|
|
5
5
|
import { SpannerTransaction } from '../spanner-transaction.js';
|
|
6
|
-
import type { SpannerOutboxEvent } from './event.js';
|
|
7
6
|
import { SpannerOutboxSender } from './sender.js';
|
|
8
7
|
/**
|
|
9
8
|
* A {@link SpannerTransaction} that uses an {@link OutboxEventTransaction}.
|
|
@@ -24,6 +23,6 @@ export type SpannerOutboxTransactionOption = {
|
|
|
24
23
|
*/
|
|
25
24
|
export declare class SpannerOutboxTransactionRunner extends OutboxTransactionRunner<SpannerOutboxTransaction> {
|
|
26
25
|
readonly entityManager: SpannerEntityManager;
|
|
27
|
-
constructor(entityManager: SpannerEntityManager, outboxEventType: Type<
|
|
26
|
+
constructor(entityManager: SpannerEntityManager, outboxEventType: Type<OutboxEvent>, sender: SpannerOutboxSender, logger: Logger);
|
|
28
27
|
protected runStateTransaction<RT>(eventTransactionFactory: () => OutboxEventTransaction, runFn: (transaction: SpannerOutboxTransaction) => Promise<RT>): Promise<RT>;
|
|
29
28
|
}
|
|
@@ -34,11 +34,6 @@ export type SpannerOutboxSenderOptions = OutboxEventSenderOptions & {
|
|
|
34
34
|
* Defaults to `leaseExpiration`.
|
|
35
35
|
*/
|
|
36
36
|
readonly leaseExpirationColumn?: string;
|
|
37
|
-
/**
|
|
38
|
-
* The name of the column used to store the timestamp at which the event was published.
|
|
39
|
-
* Defaults to `publishedAt`.
|
|
40
|
-
*/
|
|
41
|
-
readonly publishedAtColumn?: string;
|
|
42
37
|
/**
|
|
43
38
|
* The index used to fetch events.
|
|
44
39
|
*/
|
|
@@ -63,10 +58,6 @@ export declare class SpannerOutboxSender extends OutboxEventSender {
|
|
|
63
58
|
* The name of the column used for the {@link OutboxEvent.leaseExpiration} property.
|
|
64
59
|
*/
|
|
65
60
|
readonly leaseExpirationColumn: string;
|
|
66
|
-
/**
|
|
67
|
-
* The name of the column used for the {@link OutboxEvent.publishedAt} property.
|
|
68
|
-
*/
|
|
69
|
-
readonly publishedAtColumn: string;
|
|
70
61
|
/**
|
|
71
62
|
* The index used to fetch events.
|
|
72
63
|
*/
|
|
@@ -9,10 +9,6 @@ const DEFAULT_ID_COLUMN = 'id';
|
|
|
9
9
|
* The default name for the {@link OutboxEvent.leaseExpiration} column.
|
|
10
10
|
*/
|
|
11
11
|
const DEFAULT_LEASE_EXPIRATION_COLUMN = 'leaseExpiration';
|
|
12
|
-
/**
|
|
13
|
-
* The default name for the {@link OutboxEvent.publishedAt} column.
|
|
14
|
-
*/
|
|
15
|
-
const DEFAULT_PUBLISHED_AT_COLUMN = 'publishedAt';
|
|
16
12
|
/**
|
|
17
13
|
* An {@link OutboxEventSender} that uses a Spanner table to store events.
|
|
18
14
|
*/
|
|
@@ -32,10 +28,6 @@ export class SpannerOutboxSender extends OutboxEventSender {
|
|
|
32
28
|
* The name of the column used for the {@link OutboxEvent.leaseExpiration} property.
|
|
33
29
|
*/
|
|
34
30
|
leaseExpirationColumn;
|
|
35
|
-
/**
|
|
36
|
-
* The name of the column used for the {@link OutboxEvent.publishedAt} property.
|
|
37
|
-
*/
|
|
38
|
-
publishedAtColumn;
|
|
39
31
|
/**
|
|
40
32
|
* The index used to fetch events.
|
|
41
33
|
*/
|
|
@@ -75,8 +67,6 @@ export class SpannerOutboxSender extends OutboxEventSender {
|
|
|
75
67
|
this.idColumn = options.idColumn ?? DEFAULT_ID_COLUMN;
|
|
76
68
|
this.leaseExpirationColumn =
|
|
77
69
|
options.leaseExpirationColumn ?? DEFAULT_LEASE_EXPIRATION_COLUMN;
|
|
78
|
-
this.publishedAtColumn =
|
|
79
|
-
options.publishedAtColumn ?? DEFAULT_PUBLISHED_AT_COLUMN;
|
|
80
70
|
this.index = options.index;
|
|
81
71
|
({
|
|
82
72
|
fetchEventsSql: this.fetchEventsSql,
|
|
@@ -93,11 +83,7 @@ export class SpannerOutboxSender extends OutboxEventSender {
|
|
|
93
83
|
buildSql() {
|
|
94
84
|
const table = this.entityManager.sqlTableName(this.outboxEventType);
|
|
95
85
|
const tableWithIndex = this.entityManager.sqlTableName(this.outboxEventType, { index: this.index });
|
|
96
|
-
const noLeaseFilter =
|
|
97
|
-
\`${this.leaseExpirationColumn}\` IS NULL OR
|
|
98
|
-
\`${this.leaseExpirationColumn}\` < @currentTime
|
|
99
|
-
) AND
|
|
100
|
-
\`${this.publishedAtColumn}\` IS NULL`;
|
|
86
|
+
const noLeaseFilter = `\`${this.leaseExpirationColumn}\` IS NULL OR \`${this.leaseExpirationColumn}\` < @currentTime`;
|
|
101
87
|
let fetchFilter = noLeaseFilter;
|
|
102
88
|
if (this.sharding) {
|
|
103
89
|
const { column, count } = this.sharding;
|
|
@@ -126,11 +112,8 @@ export class SpannerOutboxSender extends OutboxEventSender {
|
|
|
126
112
|
THEN RETURN
|
|
127
113
|
${this.entityManager.sqlColumns(this.outboxEventType)}`;
|
|
128
114
|
const successfulUpdateSql = `
|
|
129
|
-
|
|
115
|
+
DELETE FROM
|
|
130
116
|
${table}
|
|
131
|
-
SET
|
|
132
|
-
\`${this.leaseExpirationColumn}\` = '9999-12-31T00:00:00.000Z',
|
|
133
|
-
\`${this.publishedAtColumn}\` = @currentTime
|
|
134
117
|
WHERE
|
|
135
118
|
\`${this.idColumn}\` IN UNNEST(@ids)`;
|
|
136
119
|
const failedUpdateSql = `
|
|
@@ -173,7 +156,7 @@ export class SpannerOutboxSender extends OutboxEventSender {
|
|
|
173
156
|
if (successfulSends.length > 0) {
|
|
174
157
|
batchUpdates.push({
|
|
175
158
|
sql: this.successfulUpdateSql,
|
|
176
|
-
params: { ids: successfulSends
|
|
159
|
+
params: { ids: successfulSends },
|
|
177
160
|
});
|
|
178
161
|
}
|
|
179
162
|
if (failedSends.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@causa/runtime-google",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.1",
|
|
4
4
|
"description": "An extension to the Causa runtime SDK (`@causa/runtime`), providing Google-specific features.",
|
|
5
5
|
"repository": "github:causa-io/runtime-typescript-google",
|
|
6
6
|
"license": "ISC",
|
|
@@ -29,20 +29,20 @@
|
|
|
29
29
|
"test:cov": "npm run test -- --coverage"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@causa/runtime": ">= 0.27.
|
|
32
|
+
"@causa/runtime": ">= 0.27.1 < 1.0.0",
|
|
33
33
|
"@google-cloud/precise-date": "^4.0.0",
|
|
34
34
|
"@google-cloud/pubsub": "^4.10.0",
|
|
35
35
|
"@google-cloud/spanner": "^7.18.1",
|
|
36
36
|
"@google-cloud/tasks": "^5.5.2",
|
|
37
37
|
"@grpc/grpc-js": "^1.12.6",
|
|
38
|
-
"@nestjs/common": "^11.0.
|
|
39
|
-
"@nestjs/config": "^4.0.
|
|
40
|
-
"@nestjs/core": "^11.0.
|
|
38
|
+
"@nestjs/common": "^11.0.11",
|
|
39
|
+
"@nestjs/config": "^4.0.1",
|
|
40
|
+
"@nestjs/core": "^11.0.11",
|
|
41
41
|
"@nestjs/passport": "^11.0.5",
|
|
42
42
|
"@nestjs/terminus": "^11.0.0",
|
|
43
43
|
"class-transformer": "^0.5.1",
|
|
44
44
|
"class-validator": "^0.14.1",
|
|
45
|
-
"express": "^
|
|
45
|
+
"express": "^5.0.1",
|
|
46
46
|
"firebase-admin": "^13.1.0",
|
|
47
47
|
"jsonwebtoken": "^9.0.2",
|
|
48
48
|
"passport-http-bearer": "^1.0.1",
|
|
@@ -50,19 +50,19 @@
|
|
|
50
50
|
"reflect-metadata": "^0.2.2"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@nestjs/testing": "^11.0.
|
|
54
|
-
"@swc/core": "^1.11.
|
|
53
|
+
"@nestjs/testing": "^11.0.11",
|
|
54
|
+
"@swc/core": "^1.11.7",
|
|
55
55
|
"@swc/jest": "^0.2.37",
|
|
56
56
|
"@tsconfig/node22": "^22.0.0",
|
|
57
57
|
"@types/jest": "^29.5.14",
|
|
58
58
|
"@types/jsonwebtoken": "^9.0.9",
|
|
59
|
-
"@types/node": "^22.13.
|
|
59
|
+
"@types/node": "^22.13.9",
|
|
60
60
|
"@types/passport-http-bearer": "^1.0.41",
|
|
61
61
|
"@types/supertest": "^6.0.2",
|
|
62
62
|
"@types/uuid": "^10.0.0",
|
|
63
63
|
"dotenv": "^16.4.7",
|
|
64
64
|
"eslint": "^9.21.0",
|
|
65
|
-
"eslint-config-prettier": "^10.0.
|
|
65
|
+
"eslint-config-prettier": "^10.0.2",
|
|
66
66
|
"eslint-plugin-prettier": "^5.2.3",
|
|
67
67
|
"jest": "^29.7.0",
|
|
68
68
|
"jest-extended": "^4.0.2",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
"supertest": "^7.0.0",
|
|
71
71
|
"ts-jest": "^29.2.6",
|
|
72
72
|
"ts-node": "^10.9.2",
|
|
73
|
-
"typescript": "^5.
|
|
74
|
-
"typescript-eslint": "^8.
|
|
73
|
+
"typescript": "^5.8.2",
|
|
74
|
+
"typescript-eslint": "^8.26.0",
|
|
75
75
|
"uuid": "^11.1.0"
|
|
76
76
|
}
|
|
77
77
|
}
|