@friggframework/devtools 2.0.0--canary.580.f1cb41c.0 → 2.0.0--canary.580.9716b6d.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.
@@ -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();
@@ -501,6 +531,10 @@ class AuroraBuilder extends InfrastructureBuilder {
501
531
  result.environment.DATABASE_PORT = String(dbConfig.port || 5432);
502
532
  result.environment.DATABASE_NAME = dbConfig.database || 'frigg';
503
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;
504
538
 
505
539
  console.log(` ✅ Using existing cluster: ${dbConfig.endpoint}`);
506
540
  }
@@ -731,13 +765,18 @@ exports.handler = async (event, context) => {
731
765
  result.environment.DATABASE_HOST = discoveredResources.auroraClusterEndpoint;
732
766
  result.environment.DATABASE_PORT = String(discoveredResources.auroraPort || 5432);
733
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;
734
772
 
735
773
  // Note: DATABASE_URL is NOT set here to avoid Serverless variable resolution errors
736
774
  // The application (Frigg Core) should construct it at runtime from:
737
- // DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD
775
+ // DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD, DATABASE_URL_PARAMS
738
776
 
739
777
  console.log(' ℹ️ No Secrets Manager secret found - set DATABASE_USER and DATABASE_PASSWORD in Lambda environment');
740
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.');
741
780
  console.log(' ℹ️ Or enable autoCreateCredentials=true to automatically create and rotate credentials');
742
781
  }
743
782
 
@@ -797,35 +836,11 @@ exports.handler = async (event, context) => {
797
836
  return `{{resolve:secretsmanager:${secretRefValue}:SecretString:password}}`;
798
837
  };
799
838
 
800
- // Pool + timeout query params:
801
- // connection_limit=1 — one pg connection per Lambda container;
802
- // rely on Lambda concurrency for parallelism
803
- // rather than per-process pooling (AWS RDS/
804
- // Lambda best practice).
805
- // pool_timeout=10 — throw P2024 instead of waiting forever for
806
- // a pool slot.
807
- // connect_timeout=10 — bound TCP/TLS handshake to 10s.
808
- // socket_timeout=60 — kill the client socket if the server
809
- // never responds (dead NAT/VPC route case).
810
- // options=-c statement_timeout=30000 -c lock_timeout=10000
811
- // — Postgres-side hard caps on query and
812
- // lock-wait duration; queries aborting
813
- // with SQLSTATE 57014 / 55P03 surface as
814
- // errors instead of 15-minute Lambda
815
- // timeouts. URL-encoded per Postgres libpq
816
- // conventions (space→%20, `=`→%3D inside
817
- // the options value).
818
- const queryParams = [
819
- 'connection_limit=1',
820
- 'pool_timeout=10',
821
- 'connect_timeout=10',
822
- 'socket_timeout=60',
823
- 'options=-c%20statement_timeout%3D30000%20-c%20lock_timeout%3D10000',
824
- ].join('&');
825
-
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.
826
841
  return {
827
842
  'Fn::Sub': [
828
- `postgresql://\${Username}:\${Password}@\${Host}:\${Port}/\${Database}?${queryParams}`,
843
+ `postgresql://\${Username}:\${Password}@\${Host}:\${Port}/\${Database}?${LAMBDA_DATABASE_URL_QUERY_PARAMS}`,
829
844
  {
830
845
  Username: resolveSecretRef(secretRef),
831
846
  Password: resolveSecretPassword(secretRef),
@@ -561,9 +561,12 @@ describe('AuroraBuilder', () => {
561
561
  expect(dbUrl['Fn::Sub'][0]).toMatch(
562
562
  /^postgresql:\/\/\$\{Username\}:\$\{Password\}@\$\{Host\}:\$\{Port\}\/\$\{Database\}\?/
563
563
  );
564
- expect(dbUrl['Fn::Sub'][0]).toContain('connection_limit=1');
565
- expect(dbUrl['Fn::Sub'][0]).toContain('pool_timeout=10');
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');
566
568
  expect(dbUrl['Fn::Sub'][0]).toContain('statement_timeout%3D30000');
569
+ expect(dbUrl['Fn::Sub'][0]).toContain('lock_timeout%3D10000');
567
570
 
568
571
  // The Username and Password should use Fn::Sub to resolve the secret Ref, not literal "[object Object]"
569
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--canary.580.f1cb41c.0",
4
+ "version": "2.0.0--canary.580.9716b6d.0",
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--canary.580.f1cb41c.0",
29
- "@friggframework/schemas": "2.0.0--canary.580.f1cb41c.0",
30
- "@friggframework/test": "2.0.0--canary.580.f1cb41c.0",
28
+ "@friggframework/core": "2.0.0--canary.580.9716b6d.0",
29
+ "@friggframework/schemas": "2.0.0--canary.580.9716b6d.0",
30
+ "@friggframework/test": "2.0.0--canary.580.9716b6d.0",
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--canary.580.f1cb41c.0",
59
- "@friggframework/prettier-config": "2.0.0--canary.580.f1cb41c.0",
58
+ "@friggframework/eslint-config": "2.0.0--canary.580.9716b6d.0",
59
+ "@friggframework/prettier-config": "2.0.0--canary.580.9716b6d.0",
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": "f1cb41cac2478873b9f7de4f2021848d85587a2a"
91
+ "gitHead": "9716b6d61164b122128921fcdbed420549a0fe44"
92
92
  }