Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add user mbdscore sync workers and cronjob #1838

Merged
merged 3 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
"test:qfRoundHistoryRepository": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/repositories/qfRoundHistoryRepository.test.ts",
"test:qfRoundService": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/services/qfRoundService.test.ts",
"test:project": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/entities/project.test.ts",
"test:syncUsersModelScore": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/services/cronJobs/syncUsersModelScore.test.ts",
"test:notifyDonationsWithSegment": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/services/cronJobs/notifyDonationsWithSegment.test.ts",
"test:checkProjectVerificationStatus": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/services/cronJobs/checkProjectVerificationStatus.test.ts",
"test:statusReasonResolver": "NODE_ENV=test mocha ./test/pre-test-scripts.ts ./src/resolvers/statusReasonResolver.test.ts",
Expand Down
56 changes: 56 additions & 0 deletions src/repositories/qfRoundRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
getProjectDonationsSqrtRootSum,
getQfRoundTotalSqrtRootSumSquared,
getQfRoundStats,
findUsersWithoutMBDScoreInActiveAround,
} from './qfRoundRepository';
import { Project } from '../entities/project';
import { refreshProjectEstimatedMatchingView } from '../services/projectViewsService';
Expand All @@ -26,6 +27,11 @@ describe(
'getProjectDonationsSqrtRootSum test cases',
getProjectDonationsSqrRootSumTests,
);

describe(
'findUsersWithoutMBDScoreInActiveAround test cases',
findUsersWithoutMBDScoreInActiveAroundTestCases,
);
describe(
'getQfRoundTotalProjectsDonationsSum test cases',
getQfRoundTotalProjectsDonationsSumTestCases,
Expand All @@ -41,6 +47,56 @@ describe(
describe('findQfRoundById test cases', findQfRoundByIdTestCases);
describe('findQfRoundBySlug test cases', findQfRoundBySlugTestCases);

function findUsersWithoutMBDScoreInActiveAroundTestCases() {
it('should find users without score that donated in the round', async () => {
await QfRound.update({}, { isActive: false });
const qfRound = QfRound.create({
isActive: true,
name: 'test',
allocatedFund: 100,
minimumPassportScore: 8,
slug: new Date().getTime().toString(),
beginDate: new Date(),
endDate: moment().add(10, 'days').toDate(),
});
await qfRound.save();
const project = await saveProjectDirectlyToDb(createProjectData());
project.qfRounds = [qfRound];
await project.save();

const user = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
const user2 = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
await saveDonationDirectlyToDb(
{
...createDonationData(),
segmentNotified: false,
qfRoundId: qfRound.id,
status: 'verified',
},
user.id,
project.id,
);

await saveDonationDirectlyToDb(
{
...createDonationData(),
segmentNotified: false,
qfRoundId: qfRound.id,
status: 'verified',
},
user2.id,
project.id,
);

const userIds = await findUsersWithoutMBDScoreInActiveAround();
assert.equal(userIds.length, 2);
assert.isTrue(userIds.includes(user.id) && userIds.includes(user2.id));

qfRound.isActive = false;
await qfRound.save();
});
}

function getProjectDonationsSqrRootSumTests() {
let qfRound: QfRound;
let project: Project;
Expand Down
29 changes: 29 additions & 0 deletions src/repositories/qfRoundRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const qfRoundEstimatedMatchingParamsCacheDuration = Number(
process.env.QF_ROUND_ESTIMATED_MATCHING_CACHE_DURATION || 60000,
);

const qfRoundUsersMissedMBDScore = Number(
process.env.QF_ROUND_USERS_MISSED_SCORE || 0,
);

const qfRoundsCacheDuration =
(config.get('QF_ROUND_AND_MAIN_CATEGORIES_CACHE_DURATION') as number) ||
1000 * 60 * 2;
Expand Down Expand Up @@ -172,6 +176,31 @@ export const findActiveQfRound = async (
return query.cache('findActiveQfRound', qfRoundsCacheDuration).getOne();
};

export const findUsersWithoutMBDScoreInActiveAround = async (): Promise<
number[]
> => {
const activeQfRoundId =
(await findActiveQfRound())?.id || qfRoundUsersMissedMBDScore;

if (!activeQfRoundId || activeQfRoundId === 0) return [];

const usersMissingMDBScore = await QfRound.query(
`
SELECT DISTINCT d."userId"
FROM public.donation d
LEFT JOIN user_qf_round_model_score uqrms ON d."userId" = uqrms."userId" AND uqrms."qfRoundId" = $1
WHERE d."qfRoundId" = $1
AND d.status = 'verified'
AND uqrms.id IS NULL
AND d."userId" IS NOT NULL
ORDER BY d."userId";
`,
[activeQfRoundId],
);

return usersMissingMDBScore.map(user => user.userId);
};
Comment on lines +179 to +202
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve error handling and security in the new function.

The new findUsersWithoutMBDScoreInActiveAround function is a good addition, but there are a few areas for improvement:

  1. Consider handling the case where activeQfRoundId is 0 more explicitly. The current implementation will return an empty array, which might not be the intended behavior.

  2. While using QfRound.query likely provides some protection against SQL injection, it's generally safer to use parameterized queries consistently. Consider using the query builder or ORM methods instead of raw SQL for better security and maintainability.

  3. Add error handling for potential database query failures.

Here's a suggested refactor to address these points:

export const findUsersWithoutMBDScoreInActiveAround = async (): Promise<number[]> => {
  try {
    const activeQfRound = await findActiveQfRound();
    const activeQfRoundId = activeQfRound?.id ?? qfRoundUsersMissedMBDScore;

    if (!activeQfRoundId) {
      logger.warn('No active QF round found and no fallback ID provided');
      return [];
    }

    const usersMissingMDBScore = await Donation.createQueryBuilder('d')
      .select('DISTINCT d.userId', 'userId')
      .leftJoin(UserQfRoundModelScore, 'uqrms', 'uqrms.userId = d.userId AND uqrms.qfRoundId = :qfRoundId', { qfRoundId: activeQfRoundId })
      .where('d.qfRoundId = :qfRoundId', { qfRoundId: activeQfRoundId })
      .andWhere('d.status = :status', { status: 'verified' })
      .andWhere('uqrms.id IS NULL')
      .andWhere('d.userId IS NOT NULL')
      .orderBy('d.userId')
      .getRawMany();

    return usersMissingMDBScore.map(user => user.userId);
  } catch (error) {
    logger.error('Error finding users without MBD score', { error });
    throw error;
  }
};

This refactored version uses the query builder for better security, includes error handling, and more explicitly handles the case where no active QF round is found.


export const findQfRoundById = async (id: number): Promise<QfRound | null> => {
return QfRound.createQueryBuilder('qf_round').where(`id = ${id}`).getOne();
};
Expand Down
6 changes: 6 additions & 0 deletions src/server/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import { runCheckUserSuperTokenBalancesJob } from '../services/cronJobs/checkUse
import { runCheckPendingRecurringDonationsCronJob } from '../services/cronJobs/syncRecurringDonationsWithNetwork';
import { runCheckQRTransactionJob } from '../services/cronJobs/checkQRTransactionJob';
import { addClient } from '../services/sse/sse';
import { runCheckPendingUserModelScoreCronjob } from '../services/cronJobs/syncUsersModelScore';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent function naming: 'Cronjob' vs 'CronJob'

The function name runCheckPendingUserModelScoreCronjob does not follow the existing naming convention where CronJob is capitalized with a capital 'J'. For consistency, consider renaming the function to runCheckPendingUserModelScoreCronJob.

Apply this diff to correct the function name:

-import { runCheckPendingUserModelScoreCronjob } from '../services/cronJobs/syncUsersModelScore';
+import { runCheckPendingUserModelScoreCronJob } from '../services/cronJobs/syncUsersModelScore';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { runCheckPendingUserModelScoreCronjob } from '../services/cronJobs/syncUsersModelScore';
import { runCheckPendingUserModelScoreCronJob } from '../services/cronJobs/syncUsersModelScore';


Resource.validate = validate;

Expand Down Expand Up @@ -366,6 +367,11 @@ export async function bootstrap() {
runCheckProjectVerificationStatus();
}

// If we need to deactivate the process use the env var NO MORE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect environment variable mentioned in the comment

The comment mentions use the env var NO MORE, which does not correspond to the environment variable used in the code. Update the comment to accurately reflect the correct environment variable SYNC_USERS_MBD_SCORE_ACTIVE.

Apply this diff to update the comment:

-// If we need to deactivate the process use the env var NO MORE
+// To deactivate the process, set SYNC_USERS_MBD_SCORE_ACTIVE to 'false'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// If we need to deactivate the process use the env var NO MORE
// To deactivate the process, set SYNC_USERS_MBD_SCORE_ACTIVE to 'false'

if (process.env.SYNC_USERS_MBD_SCORE_ACTIVE === 'true') {
runCheckPendingUserModelScoreCronjob();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent function naming: 'Cronjob' vs 'CronJob'

The function runCheckPendingUserModelScoreCronjob() does not follow the naming convention used elsewhere in the codebase, where CronJob is capitalized with a capital 'J'. Consider renaming it to runCheckPendingUserModelScoreCronJob() for consistency.

Apply this diff to correct the function call:

-          runCheckPendingUserModelScoreCronjob();
+          runCheckPendingUserModelScoreCronJob();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
runCheckPendingUserModelScoreCronjob();
runCheckPendingUserModelScoreCronJob();

}

// If we need to deactivate the process use the env var NO MORE
// if (process.env.GIVING_BLOCKS_SERVICE_ACTIVE === 'true') {
// runGivingBlocksProjectSynchronization();
Expand Down
85 changes: 85 additions & 0 deletions src/services/cronJobs/syncUsersModelScore.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { assert } from 'chai';
import moment from 'moment';
import {
createDonationData,
createProjectData,
generateRandomEtheriumAddress,
saveDonationDirectlyToDb,
saveProjectDirectlyToDb,
saveUserDirectlyToDb,
} from '../../../test/testUtils';
import { QfRound } from '../../entities/qfRound';
import { updateUsersWithoutMBDScoreInRound } from './syncUsersModelScore';
import { UserQfRoundModelScore } from '../../entities/userQfRoundModelScore';

describe(
'updateUsersWithoutMBDScoreInRound() test cases',
updateUsersWithoutMBDScoreInRoundTestCases,
);

function updateUsersWithoutMBDScoreInRoundTestCases() {
// for tests it return 1, useful to test cronjob logic and worker
it('should save the score for users that donated in the round', async () => {
await QfRound.update({}, { isActive: false });
const qfRound = QfRound.create({
isActive: true,
name: 'test',
allocatedFund: 100,
minimumPassportScore: 8,
slug: new Date().getTime().toString(),
beginDate: new Date(),
endDate: moment().add(10, 'days').toDate(),
});
await qfRound.save();
const project = await saveProjectDirectlyToDb(createProjectData());
project.qfRounds = [qfRound];
await project.save();

const user = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
const user2 = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
await saveDonationDirectlyToDb(
{
...createDonationData(),
segmentNotified: false,
qfRoundId: qfRound.id,
status: 'verified',
},
user.id,
project.id,
);

await saveDonationDirectlyToDb(
{
...createDonationData(),
segmentNotified: false,
qfRoundId: qfRound.id,
status: 'verified',
},
user2.id,
project.id,
);

await updateUsersWithoutMBDScoreInRound();

const user1ModelScore = await UserQfRoundModelScore.createQueryBuilder(
'score',
)
.where('score."userId" = :userId', { userId: user.id })
.andWhere('score."qfRoundId" = :qfRoundId', { qfRoundId: qfRound.id })
.getOne();

const user2ModelScore = await UserQfRoundModelScore.createQueryBuilder(
'score',
)
.where('score."userId" = :userId', { userId: user2.id })
.andWhere('score."qfRoundId" = :qfRoundId', { qfRoundId: qfRound.id })
.getOne();

// base values for mocks
assert.equal(user1ModelScore?.score, 1);
assert.equal(user2ModelScore?.score, 1);

qfRound.isActive = false;
await qfRound.save();
});
}
63 changes: 63 additions & 0 deletions src/services/cronJobs/syncUsersModelScore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { schedule } from 'node-cron';
import { spawn, Worker, Thread } from 'threads';
import config from '../../config';
import { logger } from '../../utils/logger';
import {
findActiveQfRound,
findUsersWithoutMBDScoreInActiveAround,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Possible Typo in Function Name 'findUsersWithoutMBDScoreInActiveAround'

The function name findUsersWithoutMBDScoreInActiveAround on line 7 might contain a typo. Consider renaming it to findUsersWithoutMBDScoreInActiveRound for clarity and consistency.

} from '../../repositories/qfRoundRepository';
import { findUserById } from '../../repositories/userRepository';
import { UserQfRoundModelScore } from '../../entities/userQfRoundModelScore';

const cronJobTime =
(config.get('MAKE_UNREVIEWED_PROJECT_LISTED_CRONJOB_EXPRESSION') as string) ||
'0 0 * * * *';
Comment on lines +12 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect Configuration Variable Used for Cron Job Schedule

The cron job schedule is retrieved using the config key MAKE_UNREVIEWED_PROJECT_LISTED_CRONJOB_EXPRESSION on lines 14-15, which appears unrelated to this cron job's functionality. It's recommended to create a new configuration key specific to this cron job, such as SYNC_USERS_MODEL_SCORE_CRONJOB_EXPRESSION.

Apply this diff to use the correct configuration variable:

- const cronJobTime =
-   (config.get('MAKE_UNREVIEWED_PROJECT_LISTED_CRONJOB_EXPRESSION') as string) ||
-   '0 0 * * * *';
+ const cronJobTime =
+   (config.get('SYNC_USERS_MODEL_SCORE_CRONJOB_EXPRESSION') as string) ||
+   '0 0 * * * *';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const cronJobTime =
(config.get('MAKE_UNREVIEWED_PROJECT_LISTED_CRONJOB_EXPRESSION') as string) ||
'0 0 * * * *';
const cronJobTime =
(config.get('SYNC_USERS_MODEL_SCORE_CRONJOB_EXPRESSION') as string) ||
'0 0 * * * *';


const qfRoundUsersMissedMBDScore = Number(
process.env.QF_ROUND_USERS_MISSED_SCORE || 0,
);

export const runCheckPendingUserModelScoreCronjob = () => {
logger.debug(
'runCheckPendingUserModelScoreCronjob() has been called, cronJobTime',
cronJobTime,
);
schedule(cronJobTime, async () => {
await updateUsersWithoutMBDScoreInRound();
});
};

export const updateUsersWithoutMBDScoreInRound = async () => {
const worker = await spawn(
new Worker('../../workers/userMBDScoreSyncWorker'),
);
Comment on lines +31 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure Correct Worker Instantiation and Path Resolution

On lines 41-43, the worker is instantiated using new Worker('../../workers/userMBDScoreSyncWorker'). Since you have imported UserMBDScoreSyncWorker on line 11, consider using it directly or ensure that the path to the worker file is correctly resolved. This will help avoid potential issues with path resolution, especially in different environments.

const userIds = await findUsersWithoutMBDScoreInActiveAround();
const activeQfRoundId =
(await findActiveQfRound())?.id || qfRoundUsersMissedMBDScore;
if (!activeQfRoundId || activeQfRoundId === 0) return;
Comment on lines +35 to +37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify Fallback Logic for 'activeQfRoundId'

The fallback for activeQfRoundId is set to qfRoundUsersMissedMBDScore, which defaults to 0. Immediately after, you check if activeQfRoundId is falsy or zero and return. This makes the fallback redundant. Consider simplifying the logic by removing the fallback.

Apply this diff:

const activeQfRoundId =
-   (await findActiveQfRound())?.id || qfRoundUsersMissedMBDScore;
- if (!activeQfRoundId || activeQfRoundId === 0) return;
+   (await findActiveQfRound())?.id;
+ if (!activeQfRoundId) return;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const activeQfRoundId =
(await findActiveQfRound())?.id || qfRoundUsersMissedMBDScore;
if (!activeQfRoundId || activeQfRoundId === 0) return;
const activeQfRoundId =
(await findActiveQfRound())?.id;
if (!activeQfRoundId) return;


if (userIds.length === 0) return;

for (const userId of userIds) {
try {
const user = await findUserById(userId);
if (!user) continue;

const userScore = await worker.syncUserScore({
userWallet: user?.walletAddress,
});
if (userScore) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use Explicit Null Check for 'userScore'

On line 57, you check if (userScore). If userScore can be zero, this condition will fail. Consider using an explicit null check if (userScore != null) to correctly handle cases where the score is zero.

Apply this diff:

- if (userScore) {
+ if (userScore != null) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (userScore) {
if (userScore != null) {

const userScoreInRound = UserQfRoundModelScore.create({
userId,
qfRoundId: activeQfRoundId,
score: userScore,
});

await userScoreInRound.save();
}
} catch (e) {
logger.info(`User with Id ${userId} did not sync MBD score this batch`);
}
Comment on lines +58 to +60
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve Error Logging in Catch Block

In the catch block on lines 66-68, you catch an error but only log an info message without including the error details. To aid in debugging, consider logging the error at the 'error' level and include the error message.

Apply this diff to improve error logging:

} catch (e) {
-  logger.info(`User with Id ${userId} did not sync MBD score this batch`);
+  logger.error(`Failed to sync MBD score for user with Id ${userId}: ${e.message}`, e);
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (e) {
logger.info(`User with Id ${userId} did not sync MBD score this batch`);
}
} catch (e) {
logger.error(`Failed to sync MBD score for user with Id ${userId}: ${e.message}`, e);
}

}
await Thread.terminate(worker);
};
17 changes: 17 additions & 0 deletions src/workers/userMBDScoreSyncWorker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// workers/auth.js
import { expose } from 'threads/worker';
import { WorkerModule } from 'threads/dist/types/worker';
import { getGitcoinAdapter } from '../adapters/adaptersFactory';

type UsersMBDScoreSyncWorkerFunctions = 'syncUserScore';

export type UserMBDScoreSyncWorker =
WorkerModule<UsersMBDScoreSyncWorkerFunctions>;

const worker: UserMBDScoreSyncWorker = {
async syncUserScore(args: { userWallet: string }) {
return await getGitcoinAdapter().getUserAnalysisScore(args.userWallet);
},
};
Comment on lines +11 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding error handling to the syncUserScore function.

While the implementation is concise and correctly uses async/await, it lacks error handling for potential issues that may occur when calling getGitcoinAdapter().getUserAnalysisScore().

Consider wrapping the adapter call in a try-catch block to handle potential errors:

 const worker: UserMBDScoreSyncWorker = {
   async syncUserScore(args: { userWallet: string }) {
-    return await getGitcoinAdapter().getUserAnalysisScore(args.userWallet);
+    try {
+      return await getGitcoinAdapter().getUserAnalysisScore(args.userWallet);
+    } catch (error) {
+      console.error(`Error syncing score for wallet ${args.userWallet}:`, error);
+      throw error; // Re-throw the error or handle it as appropriate for your use case
+    }
   },
 };

This change will provide better visibility into any issues that occur during the score synchronization process.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const worker: UserMBDScoreSyncWorker = {
async syncUserScore(args: { userWallet: string }) {
return await getGitcoinAdapter().getUserAnalysisScore(args.userWallet);
},
};
const worker: UserMBDScoreSyncWorker = {
async syncUserScore(args: { userWallet: string }) {
try {
return await getGitcoinAdapter().getUserAnalysisScore(args.userWallet);
} catch (error) {
console.error(`Error syncing score for wallet ${args.userWallet}:`, error);
throw error; // Re-throw the error or handle it as appropriate for your use case
}
},
};


expose(worker);
Loading