@causa/runtime-google 0.35.0 → 0.35.2
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/pubsub/interceptor.d.ts +2 -3
- package/dist/pubsub/interceptor.js +4 -4
- package/dist/pubsub/publisher.js +11 -10
- package/dist/spanner/lifecycle.service.d.ts +3 -1
- package/dist/spanner/lifecycle.service.js +17 -4
- package/dist/transaction/spanner-outbox/module.js +17 -5
- package/package.json +6 -7
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { type ObjectSerializer } from '@causa/runtime';
|
|
2
|
-
import { BaseEventHandlerInterceptor, type ParsedEventRequest } from '@causa/runtime/nestjs';
|
|
2
|
+
import { BaseEventHandlerInterceptor, Logger, type ParsedEventRequest } from '@causa/runtime/nestjs';
|
|
3
3
|
import { type ExecutionContext, type Type } from '@nestjs/common';
|
|
4
4
|
import { Reflector } from '@nestjs/core';
|
|
5
5
|
import type { Request } from 'express';
|
|
6
|
-
import { PinoLogger } from 'nestjs-pino';
|
|
7
6
|
/**
|
|
8
7
|
* The ID of the Pub/Sub event handler interceptor, that can passed to the `UseEventHandler` decorator.
|
|
9
8
|
*/
|
|
@@ -35,7 +34,7 @@ declare class PubSubMessage {
|
|
|
35
34
|
*/
|
|
36
35
|
export declare class PubSubEventHandlerInterceptor extends BaseEventHandlerInterceptor {
|
|
37
36
|
protected readonly serializer: ObjectSerializer;
|
|
38
|
-
constructor(serializer: ObjectSerializer, reflector: Reflector, logger:
|
|
37
|
+
constructor(serializer: ObjectSerializer, reflector: Reflector, logger: Logger);
|
|
39
38
|
/**
|
|
40
39
|
* Parses the given request as the payload of a Pub/Sub push request.
|
|
41
40
|
*
|
|
@@ -9,11 +9,10 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
};
|
|
10
10
|
var PubSubEventHandlerInterceptor_1;
|
|
11
11
|
import { AllowMissing, IsDateType, ValidateNestedType, ValidationError, parseObject, validateObject, } from '@causa/runtime';
|
|
12
|
-
import { BadRequestError, BaseEventHandlerInterceptor, } from '@causa/runtime/nestjs';
|
|
12
|
+
import { BadRequestError, BaseEventHandlerInterceptor, Logger, } from '@causa/runtime/nestjs';
|
|
13
13
|
import { Injectable } from '@nestjs/common';
|
|
14
14
|
import { Reflector } from '@nestjs/core';
|
|
15
15
|
import { IsBase64, IsObject, IsString } from 'class-validator';
|
|
16
|
-
import { PinoLogger } from 'nestjs-pino';
|
|
17
16
|
/**
|
|
18
17
|
* The ID of the Pub/Sub event handler interceptor, that can passed to the `UseEventHandler` decorator.
|
|
19
18
|
*/
|
|
@@ -86,6 +85,7 @@ let PubSubEventHandlerInterceptor = PubSubEventHandlerInterceptor_1 = class PubS
|
|
|
86
85
|
constructor(serializer, reflector, logger) {
|
|
87
86
|
super(PUBSUB_EVENT_HANDLER_ID, reflector, logger);
|
|
88
87
|
this.serializer = serializer;
|
|
88
|
+
this.logger.setContext(PubSubEventHandlerInterceptor_1.name);
|
|
89
89
|
}
|
|
90
90
|
/**
|
|
91
91
|
* Parses the given request as the payload of a Pub/Sub push request.
|
|
@@ -148,7 +148,7 @@ let PubSubEventHandlerInterceptor = PubSubEventHandlerInterceptor_1 = class PubS
|
|
|
148
148
|
};
|
|
149
149
|
PubSubEventHandlerInterceptorWithSerializer = __decorate([
|
|
150
150
|
Injectable(),
|
|
151
|
-
__metadata("design:paramtypes", [Reflector,
|
|
151
|
+
__metadata("design:paramtypes", [Reflector, Logger])
|
|
152
152
|
], PubSubEventHandlerInterceptorWithSerializer);
|
|
153
153
|
return PubSubEventHandlerInterceptorWithSerializer;
|
|
154
154
|
}
|
|
@@ -156,6 +156,6 @@ let PubSubEventHandlerInterceptor = PubSubEventHandlerInterceptor_1 = class PubS
|
|
|
156
156
|
PubSubEventHandlerInterceptor = PubSubEventHandlerInterceptor_1 = __decorate([
|
|
157
157
|
Injectable(),
|
|
158
158
|
__metadata("design:paramtypes", [Object, Reflector,
|
|
159
|
-
|
|
159
|
+
Logger])
|
|
160
160
|
], PubSubEventHandlerInterceptor);
|
|
161
161
|
export { PubSubEventHandlerInterceptor };
|
package/dist/pubsub/publisher.js
CHANGED
|
@@ -110,29 +110,30 @@ export class PubSubPublisher {
|
|
|
110
110
|
? topicOrPreparedEvent
|
|
111
111
|
: await this.prepare(topicOrPreparedEvent, event, options);
|
|
112
112
|
const pubSubTopic = this.getTopic(topic);
|
|
113
|
-
const
|
|
113
|
+
const messageInfo = {
|
|
114
114
|
topic,
|
|
115
115
|
pubSubTopic: pubSubTopic.name,
|
|
116
116
|
};
|
|
117
117
|
if (attributes && 'eventId' in attributes) {
|
|
118
|
-
|
|
118
|
+
messageInfo.eventId = attributes.eventId;
|
|
119
119
|
}
|
|
120
120
|
try {
|
|
121
|
-
const
|
|
121
|
+
const messageId = await pubSubTopic.publishMessage({
|
|
122
122
|
data,
|
|
123
123
|
attributes,
|
|
124
124
|
orderingKey: key,
|
|
125
125
|
});
|
|
126
|
-
this.logger.info({ ...
|
|
126
|
+
this.logger.info({ publishedMessage: { ...messageInfo, messageId } }, 'Published message to Pub/Sub.');
|
|
127
127
|
}
|
|
128
128
|
catch (error) {
|
|
129
129
|
this.logger.error({
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
130
|
+
failedMessage: {
|
|
131
|
+
...messageInfo,
|
|
132
|
+
data: data.toString('base64'),
|
|
133
|
+
attributes,
|
|
134
|
+
key,
|
|
135
|
+
},
|
|
136
|
+
error: error.stack,
|
|
136
137
|
}, 'Failed to publish message to Pub/Sub.');
|
|
137
138
|
throw error;
|
|
138
139
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Logger } from '@causa/runtime/nestjs';
|
|
1
2
|
import { Database, Spanner } from '@google-cloud/spanner';
|
|
2
3
|
import { type OnApplicationShutdown } from '@nestjs/common';
|
|
3
4
|
/**
|
|
@@ -7,6 +8,7 @@ import { type OnApplicationShutdown } from '@nestjs/common';
|
|
|
7
8
|
export declare class SpannerLifecycleService implements OnApplicationShutdown {
|
|
8
9
|
private readonly spanner;
|
|
9
10
|
private readonly database;
|
|
10
|
-
|
|
11
|
+
private readonly logger;
|
|
12
|
+
constructor(spanner: Spanner, database: Database, logger: Logger);
|
|
11
13
|
onApplicationShutdown(): Promise<void>;
|
|
12
14
|
}
|
|
@@ -7,7 +7,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
+
import { Logger } from '@causa/runtime/nestjs';
|
|
10
11
|
import { Database, Spanner } from '@google-cloud/spanner';
|
|
12
|
+
import { SessionLeakError } from '@google-cloud/spanner/build/src/session-pool.js';
|
|
11
13
|
import { Injectable } from '@nestjs/common';
|
|
12
14
|
/**
|
|
13
15
|
* A private service that handles the graceful shutdown of the Spanner Database.
|
|
@@ -16,18 +18,29 @@ import { Injectable } from '@nestjs/common';
|
|
|
16
18
|
let SpannerLifecycleService = class SpannerLifecycleService {
|
|
17
19
|
spanner;
|
|
18
20
|
database;
|
|
19
|
-
|
|
21
|
+
logger;
|
|
22
|
+
constructor(spanner, database, logger) {
|
|
20
23
|
this.spanner = spanner;
|
|
21
24
|
this.database = database;
|
|
25
|
+
this.logger = logger;
|
|
22
26
|
}
|
|
23
27
|
async onApplicationShutdown() {
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
try {
|
|
29
|
+
await this.database.close();
|
|
30
|
+
this.spanner.close();
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
this.logger.error({
|
|
34
|
+
error: error.stack,
|
|
35
|
+
spannerLeaks: error instanceof SessionLeakError ? error.messages : undefined,
|
|
36
|
+
}, 'Failed to close Spanner client.');
|
|
37
|
+
}
|
|
26
38
|
}
|
|
27
39
|
};
|
|
28
40
|
SpannerLifecycleService = __decorate([
|
|
29
41
|
Injectable(),
|
|
30
42
|
__metadata("design:paramtypes", [Spanner,
|
|
31
|
-
Database
|
|
43
|
+
Database,
|
|
44
|
+
Logger])
|
|
32
45
|
], SpannerLifecycleService);
|
|
33
46
|
export { SpannerLifecycleService };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EVENT_PUBLISHER_INJECTION_NAME, Logger } from '@causa/runtime/nestjs';
|
|
2
2
|
import { ConfigService } from '@nestjs/config';
|
|
3
|
+
import { PubSubPublisher } from '../../pubsub/index.js';
|
|
3
4
|
import { SpannerEntityManager } from '../../spanner/index.js';
|
|
4
5
|
import { SpannerOutboxEvent } from './event.js';
|
|
5
6
|
import { SpannerOutboxTransactionRunner } from './runner.js';
|
|
@@ -7,11 +8,12 @@ import { SpannerOutboxSender, } from './sender.js';
|
|
|
7
8
|
/**
|
|
8
9
|
* Combines options passed to the module with the configuration (from the environment).
|
|
9
10
|
*
|
|
10
|
-
* @param
|
|
11
|
+
* @param defaultOptions Options inferred by the module itself.
|
|
12
|
+
* @param customOptions Options passed to the module by the caller.
|
|
11
13
|
* @param config The {@link ConfigService} to use.
|
|
12
14
|
* @returns The parsed {@link SpannerOutboxSenderOptions}.
|
|
13
15
|
*/
|
|
14
|
-
function parseSenderOptions(
|
|
16
|
+
function parseSenderOptions(defaultOptions, customOptions, config) {
|
|
15
17
|
function validateIntOrUndefined(name) {
|
|
16
18
|
const strValue = config.get(name);
|
|
17
19
|
if (strValue === undefined) {
|
|
@@ -34,7 +36,7 @@ function parseSenderOptions(options, config) {
|
|
|
34
36
|
const sharding = shardingColumn && shardingCount
|
|
35
37
|
? { column: shardingColumn, count: shardingCount }
|
|
36
38
|
: undefined;
|
|
37
|
-
const
|
|
39
|
+
const envOptionsWithUndefined = {
|
|
38
40
|
batchSize,
|
|
39
41
|
pollingInterval,
|
|
40
42
|
idColumn,
|
|
@@ -43,8 +45,15 @@ function parseSenderOptions(options, config) {
|
|
|
43
45
|
sharding,
|
|
44
46
|
leaseDuration,
|
|
45
47
|
};
|
|
46
|
-
|
|
48
|
+
const envOptions = Object.fromEntries(Object.entries(envOptionsWithUndefined).filter(([, v]) => v !== undefined));
|
|
49
|
+
return { ...defaultOptions, ...envOptions, ...customOptions };
|
|
47
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* The default lease duration, in milliseconds, when the publisher is Pub/Sub.
|
|
53
|
+
* Pub/Sub has a default retry/timeout of 60 seconds. This ensures the lease is long enough and the event doesn't get
|
|
54
|
+
* picked up by another instance.
|
|
55
|
+
*/
|
|
56
|
+
const DEFAULT_PUBSUB_LEASE_DURATION = 70000;
|
|
48
57
|
/**
|
|
49
58
|
* The module providing the {@link SpannerOutboxTransactionRunner}.
|
|
50
59
|
* This assumes the `SpannerModule` and an {@link EventPublisher} are available (as well as the `LoggerModule`).
|
|
@@ -69,7 +78,10 @@ export class SpannerOutboxTransactionModule {
|
|
|
69
78
|
{
|
|
70
79
|
provide: SpannerOutboxSender,
|
|
71
80
|
useFactory: (entityManager, publisher, logger, config) => {
|
|
72
|
-
const
|
|
81
|
+
const defaultOptions = publisher instanceof PubSubPublisher
|
|
82
|
+
? { leaseDuration: DEFAULT_PUBSUB_LEASE_DURATION }
|
|
83
|
+
: {};
|
|
84
|
+
const options = parseSenderOptions(defaultOptions, senderOptions, config);
|
|
73
85
|
return new SpannerOutboxSender(entityManager, outboxEventType, publisher, logger, options);
|
|
74
86
|
},
|
|
75
87
|
inject: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@causa/runtime-google",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.2",
|
|
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,12 +29,12 @@
|
|
|
29
29
|
"test:cov": "npm run test -- --coverage"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@causa/runtime": ">= 0.24.
|
|
32
|
+
"@causa/runtime": ">= 0.24.2 < 1.0.0",
|
|
33
33
|
"@google-cloud/precise-date": "^4.0.0",
|
|
34
34
|
"@google-cloud/pubsub": "^4.9.0",
|
|
35
35
|
"@google-cloud/spanner": "^7.16.0",
|
|
36
36
|
"@google-cloud/tasks": "^5.5.1",
|
|
37
|
-
"@grpc/grpc-js": "^1.12.
|
|
37
|
+
"@grpc/grpc-js": "^1.12.3",
|
|
38
38
|
"@nestjs/common": "^10.4.12",
|
|
39
39
|
"@nestjs/config": "^3.3.0",
|
|
40
40
|
"@nestjs/core": "^10.4.12",
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"express": "^4.21.1",
|
|
46
46
|
"firebase-admin": "^13.0.1",
|
|
47
47
|
"jsonwebtoken": "^9.0.2",
|
|
48
|
-
"nestjs-pino": "^4.1.0",
|
|
49
48
|
"passport-http-bearer": "^1.0.1",
|
|
50
49
|
"pino": "^9.5.0",
|
|
51
50
|
"reflect-metadata": "^0.2.2"
|
|
@@ -61,8 +60,8 @@
|
|
|
61
60
|
"@types/passport-http-bearer": "^1.0.41",
|
|
62
61
|
"@types/supertest": "^6.0.2",
|
|
63
62
|
"@types/uuid": "^10.0.0",
|
|
64
|
-
"dotenv": "^16.4.
|
|
65
|
-
"eslint": "^9.
|
|
63
|
+
"dotenv": "^16.4.6",
|
|
64
|
+
"eslint": "^9.16.0",
|
|
66
65
|
"eslint-config-prettier": "^9.1.0",
|
|
67
66
|
"eslint-plugin-prettier": "^5.2.1",
|
|
68
67
|
"jest": "^29.7.0",
|
|
@@ -72,7 +71,7 @@
|
|
|
72
71
|
"ts-jest": "^29.2.5",
|
|
73
72
|
"ts-node": "^10.9.2",
|
|
74
73
|
"typescript": "^5.7.2",
|
|
75
|
-
"typescript-eslint": "^8.
|
|
74
|
+
"typescript-eslint": "^8.17.0",
|
|
76
75
|
"uuid": "^11.0.3"
|
|
77
76
|
}
|
|
78
77
|
}
|