appwrite-utils-cli 0.0.37 → 0.0.39
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/README.md +1 -0
- package/dist/migrations/attributes.js +21 -20
- package/dist/migrations/collections.js +10 -13
- package/dist/migrations/converters.js +15 -1
- package/dist/migrations/dataLoader.d.ts +12 -21
- package/dist/migrations/dataLoader.js +168 -58
- package/dist/migrations/databases.js +2 -1
- package/dist/migrations/importController.js +6 -24
- package/dist/migrations/importDataActions.d.ts +9 -1
- package/dist/migrations/importDataActions.js +14 -2
- package/dist/migrations/indexes.js +2 -1
- package/dist/migrations/migrationHelper.js +2 -1
- package/dist/migrations/queue.js +3 -2
- package/dist/migrations/setupDatabase.js +10 -12
- package/dist/migrations/storage.js +14 -13
- package/dist/migrations/users.js +14 -36
- package/dist/utils/helperFunctions.d.ts +10 -1
- package/dist/utils/helperFunctions.js +27 -0
- package/dist/utilsController.js +2 -1
- package/package.json +2 -2
- package/src/migrations/attributes.ts +204 -143
- package/src/migrations/collections.ts +49 -33
- package/src/migrations/converters.ts +17 -1
- package/src/migrations/dataLoader.ts +232 -63
- package/src/migrations/databases.ts +4 -1
- package/src/migrations/importController.ts +13 -27
- package/src/migrations/importDataActions.ts +17 -3
- package/src/migrations/indexes.ts +4 -1
- package/src/migrations/migrationHelper.ts +9 -5
- package/src/migrations/queue.ts +5 -6
- package/src/migrations/setupDatabase.ts +35 -18
- package/src/migrations/storage.ts +50 -36
- package/src/migrations/users.ts +28 -38
- package/src/utils/helperFunctions.ts +33 -1
- package/src/utilsController.ts +3 -1
|
@@ -3,6 +3,7 @@ import { BatchSchema, OperationSchema, type Operation } from "./backup.js";
|
|
|
3
3
|
import { AttributeMappingsSchema } from "appwrite-utils";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { logger } from "./logging.js";
|
|
6
|
+
import { tryAwaitWithRetry } from "src/utils/helperFunctions.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Object that contains the context for an action that needs to be executed after import
|
|
@@ -148,11 +149,14 @@ export const updateOperation = async (
|
|
|
148
149
|
operationId: string,
|
|
149
150
|
updateFields: any
|
|
150
151
|
) => {
|
|
151
|
-
await
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
await tryAwaitWithRetry(
|
|
153
|
+
async () =>
|
|
154
|
+
await database.updateDocument(
|
|
155
|
+
"migrations",
|
|
156
|
+
"currentOperations",
|
|
157
|
+
operationId,
|
|
158
|
+
updateFields
|
|
159
|
+
)
|
|
156
160
|
);
|
|
157
161
|
};
|
|
158
162
|
|
package/src/migrations/queue.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Attribute } from "appwrite-utils";
|
|
|
3
3
|
import { createOrUpdateAttribute } from "./attributes.js";
|
|
4
4
|
import _ from "lodash";
|
|
5
5
|
import { fetchAndCacheCollectionByName } from "./collections.js";
|
|
6
|
+
import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
|
6
7
|
|
|
7
8
|
export interface QueuedOperation {
|
|
8
9
|
type: "attribute";
|
|
@@ -37,9 +38,8 @@ export const processQueue = async (db: Databases, dbId: string) => {
|
|
|
37
38
|
if (operation.collectionId) {
|
|
38
39
|
console.log(`\tFetching collection by ID: ${operation.collectionId}`);
|
|
39
40
|
try {
|
|
40
|
-
collectionFound = await
|
|
41
|
-
dbId,
|
|
42
|
-
operation.collectionId
|
|
41
|
+
collectionFound = await tryAwaitWithRetry(
|
|
42
|
+
async () => await db.getCollection(dbId, operation.collectionId!)
|
|
43
43
|
);
|
|
44
44
|
} catch (e) {
|
|
45
45
|
console.log(
|
|
@@ -70,9 +70,8 @@ export const processQueue = async (db: Databases, dbId: string) => {
|
|
|
70
70
|
// Handle non-relationship operations with a specified collectionId
|
|
71
71
|
console.log(`\tFetching collection by ID: ${operation.collectionId}`);
|
|
72
72
|
try {
|
|
73
|
-
collectionFound = await
|
|
74
|
-
dbId,
|
|
75
|
-
operation.collectionId
|
|
73
|
+
collectionFound = await tryAwaitWithRetry(
|
|
74
|
+
async () => await db.getCollection(dbId, operation.collectionId!)
|
|
76
75
|
);
|
|
77
76
|
} catch (e) {
|
|
78
77
|
console.log(
|
|
@@ -6,7 +6,11 @@ import {
|
|
|
6
6
|
wipeDatabase,
|
|
7
7
|
} from "./collections.js";
|
|
8
8
|
import { getMigrationCollectionSchemas } from "./backup.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
areCollectionNamesSame,
|
|
11
|
+
toCamelCase,
|
|
12
|
+
tryAwaitWithRetry,
|
|
13
|
+
} from "../utils/index.js";
|
|
10
14
|
import {
|
|
11
15
|
backupDatabase,
|
|
12
16
|
initOrGetBackupStorage,
|
|
@@ -28,16 +32,18 @@ export const setupMigrationDatabase = async (config: AppwriteConfig) => {
|
|
|
28
32
|
const dbCollections: Models.Collection[] = [];
|
|
29
33
|
const migrationCollectionsSetup = getMigrationCollectionSchemas();
|
|
30
34
|
try {
|
|
31
|
-
db = await database.get("migrations");
|
|
35
|
+
db = await tryAwaitWithRetry(async () => await database.get("migrations"));
|
|
32
36
|
console.log("Migrations database found");
|
|
33
37
|
} catch (e) {
|
|
34
|
-
db = await
|
|
38
|
+
db = await tryAwaitWithRetry(
|
|
39
|
+
async () => await database.create("migrations", "Migrations", true)
|
|
40
|
+
);
|
|
35
41
|
console.log("Migrations database created");
|
|
36
42
|
}
|
|
37
43
|
if (db) {
|
|
38
|
-
const collectionsPulled = await
|
|
39
|
-
Query.limit(25)
|
|
40
|
-
|
|
44
|
+
const collectionsPulled = await tryAwaitWithRetry(
|
|
45
|
+
async () => await database.listCollections(db.$id, [Query.limit(25)])
|
|
46
|
+
);
|
|
41
47
|
dbCollections.push(...collectionsPulled.collections);
|
|
42
48
|
}
|
|
43
49
|
console.log(`Collections in migrations database: ${dbCollections.length}`);
|
|
@@ -49,19 +55,24 @@ export const setupMigrationDatabase = async (config: AppwriteConfig) => {
|
|
|
49
55
|
const collectionId = toCamelCase(collectionName); // Convert name to toCamelCase for the ID
|
|
50
56
|
let collectionFound: Models.Collection | null = null;
|
|
51
57
|
try {
|
|
52
|
-
collectionFound = await
|
|
58
|
+
collectionFound = await tryAwaitWithRetry(
|
|
59
|
+
async () => await database.getCollection(db.$id, collectionId)
|
|
60
|
+
);
|
|
53
61
|
} catch (e) {
|
|
54
62
|
console.log(`Collection not found: ${collectionId}`);
|
|
55
63
|
}
|
|
56
64
|
if (!collectionFound) {
|
|
57
65
|
// Create the collection with the provided configuration
|
|
58
|
-
collectionFound = await
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
collectionFound = await tryAwaitWithRetry(
|
|
67
|
+
async () =>
|
|
68
|
+
await database.createCollection(
|
|
69
|
+
db.$id,
|
|
70
|
+
collectionId,
|
|
71
|
+
collectionName,
|
|
72
|
+
undefined,
|
|
73
|
+
collection.documentSecurity,
|
|
74
|
+
collection.enabled
|
|
75
|
+
)
|
|
65
76
|
);
|
|
66
77
|
}
|
|
67
78
|
for (const attribute of attributes) {
|
|
@@ -87,11 +98,15 @@ export const ensureDatabasesExist = async (config: AppwriteConfig) => {
|
|
|
87
98
|
});
|
|
88
99
|
const dbNames = databasesToEnsure.map((db) => db.name);
|
|
89
100
|
|
|
90
|
-
const existingDatabases = await
|
|
101
|
+
const existingDatabases = await tryAwaitWithRetry(
|
|
102
|
+
async () => await database.list([Query.equal("name", dbNames)])
|
|
103
|
+
);
|
|
91
104
|
|
|
92
105
|
for (const db of databasesToEnsure) {
|
|
93
106
|
if (!existingDatabases.databases.some((d) => d.name === db.name)) {
|
|
94
|
-
await
|
|
107
|
+
await tryAwaitWithRetry(
|
|
108
|
+
async () => await database.create(db.$id || ID.unique(), db.name, true)
|
|
109
|
+
);
|
|
95
110
|
console.log(`${db.name} database created`);
|
|
96
111
|
}
|
|
97
112
|
}
|
|
@@ -106,12 +121,14 @@ export const wipeOtherDatabases = async (
|
|
|
106
121
|
);
|
|
107
122
|
databasesToKeep.push("migrations");
|
|
108
123
|
console.log(`Databases to keep: ${databasesToKeep.join(", ")}`);
|
|
109
|
-
const allDatabases = await
|
|
124
|
+
const allDatabases = await tryAwaitWithRetry(
|
|
125
|
+
async () => await database.list([Query.limit(500)])
|
|
126
|
+
);
|
|
110
127
|
for (const db of allDatabases.databases) {
|
|
111
128
|
if (
|
|
112
129
|
!databasesToKeep.includes(db.name.toLowerCase().trim().replace(" ", ""))
|
|
113
130
|
) {
|
|
114
|
-
await database.delete(db.$id);
|
|
131
|
+
await tryAwaitWithRetry(async () => await database.delete(db.$id));
|
|
115
132
|
console.log(`Deleted database: ${db.name}`);
|
|
116
133
|
}
|
|
117
134
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { type OperationCreate, type BackupCreate } from "./backup.js";
|
|
11
11
|
import { splitIntoBatches } from "./migrationHelper.js";
|
|
12
12
|
import type { AppwriteConfig } from "appwrite-utils";
|
|
13
|
+
import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
|
13
14
|
|
|
14
15
|
export const logOperation = async (
|
|
15
16
|
db: Databases,
|
|
@@ -21,11 +22,14 @@ export const logOperation = async (
|
|
|
21
22
|
let operation;
|
|
22
23
|
if (operationId) {
|
|
23
24
|
// Update existing operation log
|
|
24
|
-
operation = await
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
operation = await tryAwaitWithRetry(
|
|
26
|
+
async () =>
|
|
27
|
+
await db.updateDocument(
|
|
28
|
+
"migrations",
|
|
29
|
+
"currentOperations",
|
|
30
|
+
operationId,
|
|
31
|
+
operationDetails
|
|
32
|
+
)
|
|
29
33
|
);
|
|
30
34
|
} else {
|
|
31
35
|
// Create new operation log
|
|
@@ -46,14 +50,15 @@ export const logOperation = async (
|
|
|
46
50
|
|
|
47
51
|
export const initOrGetBackupStorage = async (storage: Storage) => {
|
|
48
52
|
try {
|
|
49
|
-
const backupStorage = await
|
|
53
|
+
const backupStorage = await tryAwaitWithRetry(
|
|
54
|
+
async () => await storage.getBucket("backupStorage")
|
|
55
|
+
);
|
|
50
56
|
return backupStorage;
|
|
51
57
|
} catch (e) {
|
|
52
58
|
// ID backupStorage
|
|
53
59
|
// Name Backups Storage
|
|
54
|
-
const backupStorage = await
|
|
55
|
-
"backupStorage",
|
|
56
|
-
"Backups Storage"
|
|
60
|
+
const backupStorage = await tryAwaitWithRetry(
|
|
61
|
+
async () => await storage.createBucket("backupStorage", "Backups Storage")
|
|
57
62
|
);
|
|
58
63
|
return backupStorage;
|
|
59
64
|
}
|
|
@@ -65,21 +70,27 @@ export const initOrGetDocumentStorage = async (
|
|
|
65
70
|
dbName: string
|
|
66
71
|
) => {
|
|
67
72
|
try {
|
|
68
|
-
await
|
|
69
|
-
|
|
73
|
+
await tryAwaitWithRetry(
|
|
74
|
+
async () =>
|
|
75
|
+
await storage.getBucket(
|
|
76
|
+
`${config.documentBucketId}_${dbName.toLowerCase().replace(" ", "")}`
|
|
77
|
+
)
|
|
70
78
|
);
|
|
71
79
|
} catch (e) {
|
|
72
80
|
// ID documentStorage
|
|
73
81
|
// Name Document Storage
|
|
74
|
-
const documentStorage = await
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
const documentStorage = await tryAwaitWithRetry(
|
|
83
|
+
async () =>
|
|
84
|
+
await storage.createBucket(
|
|
85
|
+
`${config.documentBucketId}_${dbName.toLowerCase().replace(" ", "")}`,
|
|
86
|
+
`Document Storage ${dbName}`,
|
|
87
|
+
[
|
|
88
|
+
Permission.read("any"),
|
|
89
|
+
Permission.create("users"),
|
|
90
|
+
Permission.update("users"),
|
|
91
|
+
Permission.delete("users"),
|
|
92
|
+
]
|
|
93
|
+
)
|
|
83
94
|
);
|
|
84
95
|
return documentStorage;
|
|
85
96
|
}
|
|
@@ -102,7 +113,9 @@ export const wipeDocumentStorage = async (
|
|
|
102
113
|
if (lastFileId) {
|
|
103
114
|
queries.push(Query.cursorAfter(lastFileId));
|
|
104
115
|
}
|
|
105
|
-
const filesPulled = await
|
|
116
|
+
const filesPulled = await tryAwaitWithRetry(
|
|
117
|
+
async () => await storage.listFiles(bucketId, queries)
|
|
118
|
+
);
|
|
106
119
|
if (filesPulled.files.length === 0) {
|
|
107
120
|
console.log("No files found, done!");
|
|
108
121
|
moreFiles = false;
|
|
@@ -177,7 +190,7 @@ export const backupDatabase = async (
|
|
|
177
190
|
// Fetch and backup the database details
|
|
178
191
|
let db: Models.Database;
|
|
179
192
|
try {
|
|
180
|
-
db = await database.get(databaseId);
|
|
193
|
+
db = await tryAwaitWithRetry(async () => await database.get(databaseId));
|
|
181
194
|
} catch (e) {
|
|
182
195
|
console.error(`Error fetching database: ${e}`);
|
|
183
196
|
await logOperation(
|
|
@@ -205,10 +218,13 @@ export const backupDatabase = async (
|
|
|
205
218
|
let total = 0; // Initialize total to 0, will be updated dynamically
|
|
206
219
|
|
|
207
220
|
while (moreCollections) {
|
|
208
|
-
const collectionResponse = await
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
221
|
+
const collectionResponse = await tryAwaitWithRetry(
|
|
222
|
+
async () =>
|
|
223
|
+
await database.listCollections(databaseId, [
|
|
224
|
+
Query.limit(500), // Adjust the limit as needed
|
|
225
|
+
...(lastCollectionId ? [Query.cursorAfter(lastCollectionId)] : []),
|
|
226
|
+
])
|
|
227
|
+
);
|
|
212
228
|
|
|
213
229
|
total += collectionResponse.collections.length; // Update total with number of collections
|
|
214
230
|
|
|
@@ -218,9 +234,8 @@ export const backupDatabase = async (
|
|
|
218
234
|
} of collectionResponse.collections) {
|
|
219
235
|
let collectionDocumentCount = 0; // Initialize document count for the current collection
|
|
220
236
|
try {
|
|
221
|
-
const collection = await
|
|
222
|
-
databaseId,
|
|
223
|
-
collectionId
|
|
237
|
+
const collection = await tryAwaitWithRetry(
|
|
238
|
+
async () => await database.getCollection(databaseId, collectionId)
|
|
224
239
|
);
|
|
225
240
|
progress++;
|
|
226
241
|
data.collections.push(JSON.stringify(collection));
|
|
@@ -230,13 +245,12 @@ export const backupDatabase = async (
|
|
|
230
245
|
let moreDocuments = true;
|
|
231
246
|
|
|
232
247
|
while (moreDocuments) {
|
|
233
|
-
const documentResponse = await
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
]
|
|
248
|
+
const documentResponse = await tryAwaitWithRetry(
|
|
249
|
+
async () =>
|
|
250
|
+
await database.listDocuments(databaseId, collectionId, [
|
|
251
|
+
Query.limit(500), // Adjust the limit as needed
|
|
252
|
+
...(lastDocumentId ? [Query.cursorAfter(lastDocumentId)] : []),
|
|
253
|
+
])
|
|
240
254
|
);
|
|
241
255
|
|
|
242
256
|
total += documentResponse.documents.length; // Update total with number of documents
|
package/src/migrations/users.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import _ from "lodash";
|
|
16
16
|
import { logger } from "./logging.js";
|
|
17
17
|
import { splitIntoBatches } from "./migrationHelper.js";
|
|
18
|
+
import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
|
18
19
|
|
|
19
20
|
export class UsersController {
|
|
20
21
|
private config: AppwriteConfig;
|
|
@@ -37,49 +38,32 @@ export class UsersController {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
async wipeUsers() {
|
|
40
|
-
const
|
|
41
|
-
const allUsers = users.users;
|
|
42
|
-
let lastDocumentId: string | undefined;
|
|
43
|
-
if (users.users.length >= 200) {
|
|
44
|
-
lastDocumentId = users.users[users.users.length - 1].$id;
|
|
45
|
-
}
|
|
46
|
-
while (lastDocumentId) {
|
|
47
|
-
const moreUsers = await this.users.list([
|
|
48
|
-
Query.limit(200),
|
|
49
|
-
Query.cursorAfter(lastDocumentId),
|
|
50
|
-
]);
|
|
51
|
-
allUsers.push(...moreUsers.users);
|
|
52
|
-
if (moreUsers.users.length < 200) {
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
|
|
56
|
-
}
|
|
41
|
+
const allUsers = await this.getAllUsers();
|
|
57
42
|
console.log("Deleting all users...");
|
|
58
|
-
|
|
59
|
-
|
|
43
|
+
|
|
44
|
+
const createBatches = (finalData: any[], batchSize: number) => {
|
|
60
45
|
const finalBatches: any[][] = [];
|
|
61
|
-
for (let i = 0; i < finalData.length; i
|
|
62
|
-
|
|
63
|
-
finalBatches.push([]);
|
|
64
|
-
}
|
|
65
|
-
finalBatches[finalBatches.length - 1].push(finalData[i]);
|
|
46
|
+
for (let i = 0; i < finalData.length; i += batchSize) {
|
|
47
|
+
finalBatches.push(finalData.slice(i, i + batchSize));
|
|
66
48
|
}
|
|
67
49
|
return finalBatches;
|
|
68
50
|
};
|
|
69
|
-
|
|
51
|
+
|
|
70
52
|
let usersDeleted = 0;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
53
|
+
const batchedUserPromises = createBatches(allUsers, 50); // Batch size of 10
|
|
54
|
+
|
|
55
|
+
for (const batch of batchedUserPromises) {
|
|
56
|
+
console.log(`Deleting ${batch.length} users...`);
|
|
57
|
+
await Promise.all(
|
|
58
|
+
batch.map((user) =>
|
|
59
|
+
tryAwaitWithRetry(async () => await this.users.delete(user.$id))
|
|
60
|
+
)
|
|
61
|
+
);
|
|
62
|
+
usersDeleted += batch.length;
|
|
74
63
|
if (usersDeleted % 100 === 0) {
|
|
75
64
|
console.log(`Deleted ${usersDeleted} users...`);
|
|
76
65
|
}
|
|
77
66
|
}
|
|
78
|
-
// const batchedUserPromises = createBatches(userPromises);
|
|
79
|
-
// for (const batch of batchedUserPromises) {
|
|
80
|
-
// console.log(`Deleting ${batch.length} users...`);
|
|
81
|
-
// await Promise.all(batch);
|
|
82
|
-
// }
|
|
83
67
|
}
|
|
84
68
|
|
|
85
69
|
async getAllUsers() {
|
|
@@ -92,10 +76,13 @@ export class UsersController {
|
|
|
92
76
|
let lastDocumentId = users.users[users.users.length - 1].$id;
|
|
93
77
|
allUsers.push(...users.users);
|
|
94
78
|
while (lastDocumentId) {
|
|
95
|
-
const moreUsers = await
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
79
|
+
const moreUsers = await tryAwaitWithRetry(
|
|
80
|
+
async () =>
|
|
81
|
+
await this.users.list([
|
|
82
|
+
Query.limit(200),
|
|
83
|
+
Query.cursorAfter(lastDocumentId),
|
|
84
|
+
])
|
|
85
|
+
);
|
|
99
86
|
allUsers.push(...moreUsers.users);
|
|
100
87
|
lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
|
|
101
88
|
if (moreUsers.users.length < 200) {
|
|
@@ -137,7 +124,10 @@ export class UsersController {
|
|
|
137
124
|
return user;
|
|
138
125
|
} catch (e) {
|
|
139
126
|
if (e instanceof AppwriteException) {
|
|
140
|
-
if (
|
|
127
|
+
if (
|
|
128
|
+
e.message.toLowerCase().includes("fetch failed") ||
|
|
129
|
+
e.message.toLowerCase().includes("server error")
|
|
130
|
+
) {
|
|
141
131
|
const numberOfAttempts = numAttempts || 0;
|
|
142
132
|
if (numberOfAttempts > 5) {
|
|
143
133
|
throw e;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { AppwriteException, type Models, type Storage } from "node-appwrite";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import type { CollectionImportData } from "../migrations/dataLoader.js";
|
|
@@ -125,3 +125,35 @@ export const finalizeByAttributeMap = async (
|
|
|
125
125
|
...item.finalData,
|
|
126
126
|
});
|
|
127
127
|
};
|
|
128
|
+
|
|
129
|
+
export let numTimesFailedTotal = 0;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Tries to execute the given createFunction and retries up to 5 times if it fails.
|
|
133
|
+
*
|
|
134
|
+
* @param {() => Promise<any>} createFunction - The function to be executed.
|
|
135
|
+
* @param {number} [attemptNum=0] - The number of attempts made so far (default: 0).
|
|
136
|
+
* @return {Promise<any>} - A promise that resolves to the result of the createFunction or rejects with an error if it fails after 5 attempts.
|
|
137
|
+
*/
|
|
138
|
+
export const tryAwaitWithRetry = async <T>(
|
|
139
|
+
createFunction: () => Promise<T>,
|
|
140
|
+
attemptNum: number = 0
|
|
141
|
+
): Promise<T> => {
|
|
142
|
+
try {
|
|
143
|
+
return await createFunction();
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (
|
|
146
|
+
error instanceof AppwriteException &&
|
|
147
|
+
(error.message.toLowerCase().includes("fetch failed") ||
|
|
148
|
+
error.message.toLowerCase().includes("server error"))
|
|
149
|
+
) {
|
|
150
|
+
numTimesFailedTotal++;
|
|
151
|
+
console.log(`Fetch failed on attempt ${attemptNum}. Retrying...`);
|
|
152
|
+
if (attemptNum > 5) {
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
return tryAwaitWithRetry(createFunction, attemptNum + 1);
|
|
156
|
+
}
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
};
|
package/src/utilsController.ts
CHANGED
|
@@ -4,7 +4,7 @@ import path from "path";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import { load } from "js-yaml";
|
|
6
6
|
import { ImportDataActions } from "./migrations/importDataActions.js";
|
|
7
|
-
import {
|
|
7
|
+
import { numTimesFailedTotal } from "./utils/helperFunctions.js";
|
|
8
8
|
import { afterImportActions } from "./migrations/afterImportActions.js";
|
|
9
9
|
import {
|
|
10
10
|
type AfterImportActions,
|
|
@@ -187,6 +187,8 @@ export class UtilsController {
|
|
|
187
187
|
console.log("Import data complete.");
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
console.log("Total number of times Fetch failed: ", numTimesFailedTotal);
|
|
191
|
+
|
|
190
192
|
// if (options.checkDuplicates) {
|
|
191
193
|
// await this.checkDuplicates();
|
|
192
194
|
// }
|