@friggframework/devtools 2.0.0-next.80 → 2.0.0-next.81
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.
|
@@ -21,6 +21,36 @@ const AuroraResourceResolver = require('./aurora-resolver');
|
|
|
21
21
|
const { createEmptyDiscoveryResult } = require('../shared/types/discovery-result');
|
|
22
22
|
const { ResourceOwnership } = require('../shared/types/resource-ownership');
|
|
23
23
|
|
|
24
|
+
// Pool + timeout query params appended to DATABASE_URL for Lambda-to-Aurora
|
|
25
|
+
// connections. Chosen to make worker Lambdas fail loud and fast on any DB
|
|
26
|
+
// contention rather than silently hanging for Lambda's 900s timeout.
|
|
27
|
+
//
|
|
28
|
+
// connection_limit=2 — two pg connections per Lambda container. One is too
|
|
29
|
+
// tight: several core use cases (get-process.executeMany,
|
|
30
|
+
// field-encryption-service batches) issue in-handler
|
|
31
|
+
// Promise.all against Prisma, and would serialize
|
|
32
|
+
// behind a single slot. Two removes that cliff while
|
|
33
|
+
// still being safe against max_connections (at 4 ACU
|
|
34
|
+
// Aurora pg 15 allows ~400 connections; 200 concurrent
|
|
35
|
+
// Lambdas × 2 = 400, leaves cluster room for maint).
|
|
36
|
+
// pool_timeout=20 — wait up to 20s for a pool slot, then throw P2024.
|
|
37
|
+
// Still fail-fast relative to 900s Lambda cap; gives
|
|
38
|
+
// in-handler fan-outs headroom.
|
|
39
|
+
// connect_timeout=10 — bound TCP/TLS handshake.
|
|
40
|
+
// socket_timeout=60 — kill dead client sockets (server never responds).
|
|
41
|
+
// options=-c statement_timeout=30000 -c lock_timeout=10000
|
|
42
|
+
// — Postgres-side hard caps. A query stuck >30s aborts
|
|
43
|
+
// with SQLSTATE 57014; a lock wait >10s aborts with
|
|
44
|
+
// SQLSTATE 55P03. URL encoding per libpq URI rules
|
|
45
|
+
// (space→%20, `=`→%3D inside the options value).
|
|
46
|
+
const LAMBDA_DATABASE_URL_QUERY_PARAMS = [
|
|
47
|
+
'connection_limit=2',
|
|
48
|
+
'pool_timeout=20',
|
|
49
|
+
'connect_timeout=10',
|
|
50
|
+
'socket_timeout=60',
|
|
51
|
+
'options=-c%20statement_timeout%3D30000%20-c%20lock_timeout%3D10000',
|
|
52
|
+
].join('&');
|
|
53
|
+
|
|
24
54
|
class AuroraBuilder extends InfrastructureBuilder {
|
|
25
55
|
constructor() {
|
|
26
56
|
super();
|
|
@@ -415,9 +445,16 @@ class AuroraBuilder extends InfrastructureBuilder {
|
|
|
415
445
|
],
|
|
416
446
|
// Note: PubliclyAccessible is NOT supported on Aurora clusters
|
|
417
447
|
// It should only be set on DB instances (see FriggAuroraInstance below)
|
|
448
|
+
// MaxCapacity default bumped 1 → 4 ACU: at 0.5–1 ACU Aurora is
|
|
449
|
+
// CPU-starved under 20-way concurrent writes from a Lambda
|
|
450
|
+
// fan-out sync, which starves worker queries and compounds
|
|
451
|
+
// the tail-latency problem. 4 ACU is still cheap (scales to
|
|
452
|
+
// min when idle) and gives the DB enough headroom to
|
|
453
|
+
// absorb bursty sync traffic. Apps can still override both
|
|
454
|
+
// via app definition dbConfig.
|
|
418
455
|
ServerlessV2ScalingConfiguration: {
|
|
419
456
|
MinCapacity: dbConfig.minCapacity || 0.5,
|
|
420
|
-
MaxCapacity: dbConfig.maxCapacity ||
|
|
457
|
+
MaxCapacity: dbConfig.maxCapacity || 4,
|
|
421
458
|
},
|
|
422
459
|
EnableHttpEndpoint: false,
|
|
423
460
|
BackupRetentionPeriod: 7,
|
|
@@ -494,6 +531,10 @@ class AuroraBuilder extends InfrastructureBuilder {
|
|
|
494
531
|
result.environment.DATABASE_PORT = String(dbConfig.port || 5432);
|
|
495
532
|
result.environment.DATABASE_NAME = dbConfig.database || 'frigg';
|
|
496
533
|
result.environment.DATABASE_USER = dbConfig.username || 'postgres';
|
|
534
|
+
// Consumers that build DATABASE_URL from components at runtime MUST
|
|
535
|
+
// append `?${DATABASE_URL_PARAMS}` to get the same hang-prevention
|
|
536
|
+
// timeouts as the managed path.
|
|
537
|
+
result.environment.DATABASE_URL_PARAMS = LAMBDA_DATABASE_URL_QUERY_PARAMS;
|
|
497
538
|
|
|
498
539
|
console.log(` ✅ Using existing cluster: ${dbConfig.endpoint}`);
|
|
499
540
|
}
|
|
@@ -724,13 +765,18 @@ exports.handler = async (event, context) => {
|
|
|
724
765
|
result.environment.DATABASE_HOST = discoveredResources.auroraClusterEndpoint;
|
|
725
766
|
result.environment.DATABASE_PORT = String(discoveredResources.auroraPort || 5432);
|
|
726
767
|
result.environment.DATABASE_NAME = dbName;
|
|
768
|
+
// Consumers that build DATABASE_URL from components at runtime MUST
|
|
769
|
+
// append `?${DATABASE_URL_PARAMS}` to get the same hang-prevention
|
|
770
|
+
// timeouts as the managed path.
|
|
771
|
+
result.environment.DATABASE_URL_PARAMS = LAMBDA_DATABASE_URL_QUERY_PARAMS;
|
|
727
772
|
|
|
728
773
|
// Note: DATABASE_URL is NOT set here to avoid Serverless variable resolution errors
|
|
729
774
|
// The application (Frigg Core) should construct it at runtime from:
|
|
730
|
-
// DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD
|
|
775
|
+
// DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD, DATABASE_URL_PARAMS
|
|
731
776
|
|
|
732
777
|
console.log(' ℹ️ No Secrets Manager secret found - set DATABASE_USER and DATABASE_PASSWORD in Lambda environment');
|
|
733
778
|
console.log(' ℹ️ Application will construct DATABASE_URL at runtime from DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD');
|
|
779
|
+
console.log(' ℹ️ Append `?${DATABASE_URL_PARAMS}` to the constructed URL for pool/timeout safety.');
|
|
734
780
|
console.log(' ℹ️ Or enable autoCreateCredentials=true to automatically create and rotate credentials');
|
|
735
781
|
}
|
|
736
782
|
|
|
@@ -790,9 +836,11 @@ exports.handler = async (event, context) => {
|
|
|
790
836
|
return `{{resolve:secretsmanager:${secretRefValue}:SecretString:password}}`;
|
|
791
837
|
};
|
|
792
838
|
|
|
839
|
+
// Query params are defined at module scope (LAMBDA_DATABASE_URL_QUERY_PARAMS)
|
|
840
|
+
// so runtime-URL-construction paths can emit the same timeouts as an env var.
|
|
793
841
|
return {
|
|
794
842
|
'Fn::Sub': [
|
|
795
|
-
`postgresql://\${Username}:\${Password}@\${Host}:\${Port}/\${Database}`,
|
|
843
|
+
`postgresql://\${Username}:\${Password}@\${Host}:\${Port}/\${Database}?${LAMBDA_DATABASE_URL_QUERY_PARAMS}`,
|
|
796
844
|
{
|
|
797
845
|
Username: resolveSecretRef(secretRef),
|
|
798
846
|
Password: resolveSecretPassword(secretRef),
|
|
@@ -556,7 +556,17 @@ describe('AuroraBuilder', () => {
|
|
|
556
556
|
|
|
557
557
|
// Should use Fn::Sub with nested Fn::Sub to resolve the Ref
|
|
558
558
|
expect(dbUrl['Fn::Sub']).toBeDefined();
|
|
559
|
-
|
|
559
|
+
// Template includes pool + timeout query params to prevent
|
|
560
|
+
// silent 15-min Lambda hangs on DB contention.
|
|
561
|
+
expect(dbUrl['Fn::Sub'][0]).toMatch(
|
|
562
|
+
/^postgresql:\/\/\$\{Username\}:\$\{Password\}@\$\{Host\}:\$\{Port\}\/\$\{Database\}\?/
|
|
563
|
+
);
|
|
564
|
+
expect(dbUrl['Fn::Sub'][0]).toContain('connection_limit=2');
|
|
565
|
+
expect(dbUrl['Fn::Sub'][0]).toContain('pool_timeout=20');
|
|
566
|
+
expect(dbUrl['Fn::Sub'][0]).toContain('connect_timeout=10');
|
|
567
|
+
expect(dbUrl['Fn::Sub'][0]).toContain('socket_timeout=60');
|
|
568
|
+
expect(dbUrl['Fn::Sub'][0]).toContain('statement_timeout%3D30000');
|
|
569
|
+
expect(dbUrl['Fn::Sub'][0]).toContain('lock_timeout%3D10000');
|
|
560
570
|
|
|
561
571
|
// The Username and Password should use Fn::Sub to resolve the secret Ref, not literal "[object Object]"
|
|
562
572
|
expect(dbUrl['Fn::Sub'][1].Username['Fn::Sub']).toBeDefined();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0-next.
|
|
4
|
+
"version": "2.0.0-next.81",
|
|
5
5
|
"bin": {
|
|
6
6
|
"frigg": "./frigg-cli/index.js"
|
|
7
7
|
},
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"@babel/eslint-parser": "^7.18.9",
|
|
26
26
|
"@babel/parser": "^7.25.3",
|
|
27
27
|
"@babel/traverse": "^7.25.3",
|
|
28
|
-
"@friggframework/core": "2.0.0-next.
|
|
29
|
-
"@friggframework/schemas": "2.0.0-next.
|
|
30
|
-
"@friggframework/test": "2.0.0-next.
|
|
28
|
+
"@friggframework/core": "2.0.0-next.81",
|
|
29
|
+
"@friggframework/schemas": "2.0.0-next.81",
|
|
30
|
+
"@friggframework/test": "2.0.0-next.81",
|
|
31
31
|
"@hapi/boom": "^10.0.1",
|
|
32
32
|
"@inquirer/prompts": "^5.3.8",
|
|
33
33
|
"axios": "^1.7.2",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"validate-npm-package-name": "^5.0.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@friggframework/eslint-config": "2.0.0-next.
|
|
59
|
-
"@friggframework/prettier-config": "2.0.0-next.
|
|
58
|
+
"@friggframework/eslint-config": "2.0.0-next.81",
|
|
59
|
+
"@friggframework/prettier-config": "2.0.0-next.81",
|
|
60
60
|
"aws-sdk-client-mock": "^4.1.0",
|
|
61
61
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
62
62
|
"jest": "^30.1.3",
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
"publishConfig": {
|
|
89
89
|
"access": "public"
|
|
90
90
|
},
|
|
91
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "f928679326fe06cc56ac46e97cf268fe8f8e823e"
|
|
92
92
|
}
|