@teamkeel/functions-runtime 0.393.2 → 0.393.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamkeel/functions-runtime",
3
- "version": "0.393.2",
3
+ "version": "0.393.3",
4
4
  "description": "Internal package used by @teamkeel/sdk",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/database.js CHANGED
@@ -43,10 +43,11 @@ async function withDatabase(db, actionType, cb) {
43
43
  });
44
44
  }
45
45
 
46
- let db = null;
47
-
48
46
  const dbInstance = new AsyncLocalStorage();
49
47
 
48
+ // used to establish a singleton for our vitest environment
49
+ let vitestDb = null;
50
+
50
51
  // useDatabase will retrieve the database client set by withDatabase from the local storage
51
52
  function useDatabase() {
52
53
  // retrieve the instance of the database client from the store which is aware of
@@ -61,7 +62,10 @@ function useDatabase() {
61
62
  // which covers any test files ending in *.test.ts. Custom function code runs in a different node process which will not have this environment variable. Tests written using our testing
62
63
  // framework call actions (and in turn custom function code) over http using the ActionExecutor class
63
64
  if ("NODE_ENV" in process.env && process.env.NODE_ENV == "test") {
64
- return getDatabaseClient();
65
+ if (!vitestDb) {
66
+ vitestDb = createDatabaseClient();
67
+ }
68
+ return vitestDb;
65
69
  }
66
70
 
67
71
  // If we've gotten to this point, then we know that we are in a custom function runtime server
@@ -69,17 +73,11 @@ function useDatabase() {
69
73
  throw new Error("useDatabase must be called within a function");
70
74
  }
71
75
 
72
- // getDatabaseClient will return a brand new instance of Kysely. Every instance of Kysely
76
+ // createDatabaseClient will return a brand new instance of Kysely. Every instance of Kysely
73
77
  // represents an individual connection to the database.
74
78
  // not to be exported externally from our sdk - consumers should use useDatabase
75
- function getDatabaseClient() {
76
- // 'db' represents the singleton connection to the database which is stored
77
- // as a module scope variable.
78
- if (db) {
79
- return db;
80
- }
81
-
82
- db = new Kysely({
79
+ function createDatabaseClient() {
80
+ const db = new Kysely({
83
81
  dialect: getDialect(),
84
82
  plugins: [
85
83
  // ensures that the audit context data is written to Postgres configuration parameters
@@ -109,7 +107,6 @@ class InstrumentedPool extends pg.Pool {
109
107
  const _super = super.connect.bind(this);
110
108
  return withSpan("Database Connect", function (span) {
111
109
  span.setAttribute("dialect", process.env["KEEL_DB_CONN_TYPE"]);
112
- span.setAttribute("timeout", connectionTimeout());
113
110
  return _super(...args);
114
111
  });
115
112
  }
@@ -120,7 +117,6 @@ class InstrumentedNeonServerlessPool extends neonserverless.Pool {
120
117
  const _super = super.connect.bind(this);
121
118
  return withSpan("Database Connect", function (span) {
122
119
  span.setAttribute("dialect", process.env["KEEL_DB_CONN_TYPE"]);
123
- span.setAttribute("timeout", connectionTimeout());
124
120
  return _super(...args);
125
121
  });
126
122
  }
@@ -179,7 +175,7 @@ function getDialect() {
179
175
  // Although I doubt we will run into these freeze/thaw issues if idleTimeoutMillis is always shorter than the
180
176
  // time is takes for a lambda to freeze (which is not a constant, but could be as short as several minutes,
181
177
  // https://www.pluralsight.com/resources/blog/cloud/how-long-does-aws-lambda-keep-your-idle-functions-around-before-a-cold-start)
182
- idleTimeoutMillis: connectionTimeout(),
178
+ idleTimeoutMillis: 50000,
183
179
  connectionString: mustEnv("KEEL_DB_CONN"),
184
180
  }),
185
181
  });
@@ -187,7 +183,6 @@ function getDialect() {
187
183
  neonserverless.neonConfig.webSocketConstructor = ws;
188
184
 
189
185
  const pool = new InstrumentedNeonServerlessPool({
190
- idleTimeoutMillis: connectionTimeout(),
191
186
  connectionString: mustEnv("KEEL_DB_CONN"),
192
187
  });
193
188
 
@@ -229,17 +224,6 @@ function mustEnv(key) {
229
224
  return v;
230
225
  }
231
226
 
232
- function connectionTimeout() {
233
- const v = Number(process.env["KEEL_DB_CONN_TIMEOUT"]);
234
- if (!v || isNaN(v)) {
235
- return 45000; // 60s is our current neon suspend default
236
- }
237
- return v;
238
- }
239
-
240
- // initialise the database client at module scope level so the db variable is set
241
- getDatabaseClient();
242
-
243
- module.exports.getDatabaseClient = getDatabaseClient;
227
+ module.exports.createDatabaseClient = createDatabaseClient;
244
228
  module.exports.useDatabase = useDatabase;
245
229
  module.exports.withDatabase = withDatabase;
package/src/handleJob.js CHANGED
@@ -3,7 +3,7 @@ const {
3
3
  createJSONRPCSuccessResponse,
4
4
  JSONRPCErrorCode,
5
5
  } = require("json-rpc-2.0");
6
- const { getDatabaseClient } = require("./database");
6
+ const { createDatabaseClient } = require("./database");
7
7
  const { errorToJSONRPCResponse, RuntimeErrors } = require("./errors");
8
8
  const opentelemetry = require("@opentelemetry/api");
9
9
  const { withSpan } = require("./tracing");
@@ -25,6 +25,8 @@ async function handleJob(request, config) {
25
25
  return opentelemetry.context.with(activeContext, () => {
26
26
  // Wrapping span for the whole request
27
27
  return withSpan(request.method, async (span) => {
28
+ let db = null;
29
+
28
30
  try {
29
31
  const { createJobContextAPI, jobs } = config;
30
32
 
@@ -51,7 +53,7 @@ async function handleJob(request, config) {
51
53
  ? true
52
54
  : null;
53
55
 
54
- const db = getDatabaseClient();
56
+ db = createDatabaseClient();
55
57
  const jobFunction = jobs[request.method];
56
58
  const actionType = PROTO_ACTION_TYPES.JOB;
57
59
 
@@ -89,6 +91,10 @@ async function handleJob(request, config) {
89
91
  RuntimeErrors.UnknownError,
90
92
  message
91
93
  );
94
+ } finally {
95
+ if (db) {
96
+ await db.destroy();
97
+ }
92
98
  }
93
99
  });
94
100
  });
@@ -3,7 +3,7 @@ const {
3
3
  createJSONRPCSuccessResponse,
4
4
  JSONRPCErrorCode,
5
5
  } = require("json-rpc-2.0");
6
- const { getDatabaseClient } = require("./database");
6
+ const { createDatabaseClient } = require("./database");
7
7
  const { tryExecuteFunction } = require("./tryExecuteFunction");
8
8
  const { errorToJSONRPCResponse, RuntimeErrors } = require("./errors");
9
9
  const opentelemetry = require("@opentelemetry/api");
@@ -28,6 +28,8 @@ async function handleRequest(request, config) {
28
28
  return opentelemetry.context.with(activeContext, () => {
29
29
  // Wrapping span for the whole request
30
30
  return withSpan(request.method, async (span) => {
31
+ let db = null;
32
+
31
33
  try {
32
34
  const { createContextAPI, functions, permissionFns, actionTypes } =
33
35
  config;
@@ -62,7 +64,7 @@ async function handleRequest(request, config) {
62
64
  ? true
63
65
  : null;
64
66
 
65
- const db = getDatabaseClient();
67
+ db = createDatabaseClient();
66
68
  const customFunction = functions[request.method];
67
69
  const actionType = actionTypes[request.method];
68
70
 
@@ -122,6 +124,10 @@ async function handleRequest(request, config) {
122
124
  RuntimeErrors.UnknownError,
123
125
  message
124
126
  );
127
+ } finally {
128
+ if (db) {
129
+ await db.destroy();
130
+ }
125
131
  }
126
132
  });
127
133
  });
@@ -3,7 +3,7 @@ const {
3
3
  createJSONRPCSuccessResponse,
4
4
  JSONRPCErrorCode,
5
5
  } = require("json-rpc-2.0");
6
- const { getDatabaseClient } = require("./database");
6
+ const { createDatabaseClient } = require("./database");
7
7
  const { errorToJSONRPCResponse, RuntimeErrors } = require("./errors");
8
8
  const opentelemetry = require("@opentelemetry/api");
9
9
  const { withSpan } = require("./tracing");
@@ -24,6 +24,8 @@ async function handleSubscriber(request, config) {
24
24
  return opentelemetry.context.with(activeContext, () => {
25
25
  // Wrapping span for the whole request
26
26
  return withSpan(request.method, async (span) => {
27
+ let db = null;
28
+
27
29
  try {
28
30
  const { createSubscriberContextAPI, subscribers } = config;
29
31
 
@@ -45,7 +47,7 @@ async function handleSubscriber(request, config) {
45
47
  meta: request.meta,
46
48
  });
47
49
 
48
- const db = getDatabaseClient();
50
+ db = createDatabaseClient();
49
51
  const subscriberFunction = subscribers[request.method];
50
52
  const actionType = PROTO_ACTION_TYPES.SUBSCRIBER;
51
53
 
@@ -77,6 +79,10 @@ async function handleSubscriber(request, config) {
77
79
  RuntimeErrors.UnknownError,
78
80
  message
79
81
  );
82
+ } finally {
83
+ if (db) {
84
+ await db.destroy();
85
+ }
80
86
  }
81
87
  });
82
88
  });