-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨Ignore errors during nextcloud migration to be able to import files …
…partially for big migrations
- Loading branch information
Showing
4 changed files
with
140 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { logger } from "./logger"; | ||
|
||
type FunctionArgs = any[]; | ||
|
||
type FunctionStats = { | ||
functionName: string; | ||
successfulExecutions: number; | ||
failedExecutions: number; | ||
failedExecutionsArgs: FunctionArgs[]; | ||
}; | ||
|
||
export class FunctionExecutor { | ||
private stats: Map<string, FunctionStats> = new Map(); | ||
|
||
async executeWithRetries( | ||
fn: (...args: any[]) => Promise<any>, | ||
args: FunctionArgs, | ||
retries: number = 3, | ||
throwError: boolean = false, | ||
): Promise<any> { | ||
const functionName = fn.name; | ||
let success = false; | ||
let executionResult = null; | ||
|
||
for (let attempt = 0; attempt < retries; attempt++) { | ||
try { | ||
executionResult = await fn(...args); | ||
success = true; | ||
break; | ||
} catch (error) { | ||
executionResult = error; | ||
logger.info(`Attempt ${attempt + 1} failed for ${functionName}`, error); | ||
} | ||
} | ||
|
||
if (!success && throwError) throw executionResult; | ||
|
||
let stats = this.stats.get(functionName); | ||
if (!stats) { | ||
stats = { | ||
functionName, | ||
successfulExecutions: 0, | ||
failedExecutions: 0, | ||
failedExecutionsArgs: [] | ||
}; | ||
this.stats.set(functionName, stats); | ||
} | ||
|
||
if (success) { | ||
stats.successfulExecutions++; | ||
} else { | ||
stats.failedExecutions++; | ||
stats.failedExecutionsArgs.push( args ); | ||
} | ||
return executionResult; | ||
} | ||
|
||
async getStats() { | ||
return this.stats; | ||
} | ||
|
||
printStatistics(): void { | ||
logger.info("Execution Statistics:"); | ||
this.stats.forEach((stat) => { | ||
logger.info( | ||
`Function: ${stat.functionName}, Successful Executions: ${stat.successfulExecutions}, Failed Executions: ${stat.failedExecutions}` | ||
); | ||
}); | ||
} | ||
|
||
printFailedExecutions(): void { | ||
logger.info("Failed Executions:"); | ||
this.stats.forEach((execution) => { | ||
if (execution.failedExecutionsArgs.length > 0) { | ||
logger.info(` Function: ${execution.functionName}`); | ||
execution.failedExecutionsArgs.forEach(args => | ||
logger.info(` args: ${JSON.stringify(args)}`)); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
tdrive/backend/utils/nextcloud-migration/test/executor.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { describe, expect, test } from "@jest/globals"; | ||
import { FunctionExecutor } from "../src/executor"; | ||
|
||
//FOR LOCAL DEBUG PURPOSE ONLY, ITS NOT A TEST | ||
describe('Function Executor tests', () => { | ||
|
||
const subj = new FunctionExecutor(); | ||
|
||
test('Should successfully execute mock function', async () => { | ||
//when | ||
await subj.executeWithRetries(successFunction, [1, 2], 3); | ||
await subj.executeWithRetries(successFunction, [4, 5], 3); | ||
|
||
//then | ||
let stats = await subj.getStats(); | ||
expect(stats?.get("successFunction")?.successfulExecutions).toEqual(2); | ||
}); | ||
|
||
test('Should successfully gather arguments of the failed executions', async () => { | ||
await subj.executeWithRetries(failedFunction, [1, 2], 3); | ||
|
||
//then | ||
let stats = await subj.getStats(); | ||
expect(stats?.get("failedFunction")?.failedExecutions).toBe(1); | ||
expect(stats?.get("failedFunction")?.failedExecutionsArgs[0]).toStrictEqual([1, 2]); | ||
}); | ||
|
||
test('Should successfully gather arguments of the class member', async () => { | ||
await subj.executeWithRetries(subj.getStats.bind(this), [1, 2], 3); | ||
|
||
//then | ||
let stats = await subj.getStats(); | ||
expect(stats?.get("bound getStats")?.successfulExecutions).toEqual(1); | ||
}); | ||
|
||
const successFunction = async (a: number, b: number) => { | ||
return a + b; | ||
}; | ||
|
||
const failedFunction = async () => { | ||
throw new Error(); | ||
}; | ||
|
||
}); |