-
Notifications
You must be signed in to change notification settings - Fork 55
Expand file tree
/
Copy pathmongo.ts
More file actions
115 lines (101 loc) · 3.49 KB
/
Copy pathmongo.ts
File metadata and controls
115 lines (101 loc) · 3.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import * as mongo from 'mongodb';
import * as timers from 'timers/promises';
import { BaseMongoConfigDecoded, normalizeMongoConfig } from '../types/types.js';
/**
* Time for new connection to timeout.
*/
export const MONGO_CONNECT_TIMEOUT_MS = 10_000;
/**
* Time for individual requests to timeout the socket.
*/
export const MONGO_SOCKET_TIMEOUT_MS = 60_000;
/**
* Time for individual requests to timeout the operation.
*
* This is time spent on the cursor, not total time.
*
* Must be less than MONGO_SOCKET_TIMEOUT_MS to ensure proper error handling.
*/
export const MONGO_OPERATION_TIMEOUT_MS = 40_000;
/**
* Time for individual checksums requests to timeout the operation.
*
* This is time spent on the cursor, not total time.
*
* Must be less than MONGO_SOCKET_TIMEOUT_MS to ensure proper error handling.
*/
export const MONGO_CHECKSUM_TIMEOUT_MS = 50_000;
/**
* Same as above, but specifically for clear operations.
*
* These are retried when reaching the timeout.
*/
export const MONGO_CLEAR_OPERATION_TIMEOUT_MS = 5_000;
export interface MongoConnectionOptions {
maxPoolSize?: number;
powersyncVersion?: string;
}
/**
* Create a MongoClient for the storage database.
*/
export function createMongoClient(config: BaseMongoConfigDecoded, options?: MongoConnectionOptions) {
const normalized = normalizeMongoConfig(config);
return new mongo.MongoClient(normalized.uri, {
auth: {
username: normalized.username,
password: normalized.password
},
// Time for connection to timeout
connectTimeoutMS: MONGO_CONNECT_TIMEOUT_MS,
// Time for individual requests to timeout
socketTimeoutMS: MONGO_SOCKET_TIMEOUT_MS,
// How long to wait for new primary selection
serverSelectionTimeoutMS: 30_000,
// Identify the client
appName: options?.powersyncVersion ? `powersync-storage ${options.powersyncVersion}` : 'powersync-storage',
// Deprecated in the driver - in a future release we may have to rely on appName only.
driverInfo: {
// This is merged with the node driver info.
name: 'powersync-storage',
version: options?.powersyncVersion
},
lookup: normalized.lookup,
// Avoid too many connections:
// 1. It can overwhelm the source database.
// 2. Processing too many queries in parallel can cause the process to run out of memory.
maxPoolSize: options?.maxPoolSize ?? 8,
maxConnecting: 3,
maxIdleTimeMS: 60_000
});
}
/**
* Wait up to a minute for authentication errors to resolve.
*
* There can be a delay between an Atlas user being created, and that user being
* available on the database cluster. This works around it.
*
* This is specifically relevant for migrations and teardown - other parts of the stack
* can generate handle these failures and just retry or restart.
*/
export async function waitForAuth(db: mongo.Db) {
const start = Date.now();
while (Date.now() - start < 60_000) {
try {
await db.command({ ping: 1 });
// Success
break;
} catch (e) {
if (e.codeName == 'AuthenticationFailed') {
await timers.setTimeout(1_000);
continue;
}
throw e;
}
}
}
export const isMongoServerError = (error: any): error is mongo.MongoServerError => {
return error instanceof mongo.MongoServerError || error?.name == 'MongoServerError';
};
export const isMongoNetworkTimeoutError = (error: any): error is mongo.MongoNetworkTimeoutError => {
return error instanceof mongo.MongoNetworkTimeoutError || error?.name == 'MongoNetworkTimeoutError';
};