-
Notifications
You must be signed in to change notification settings - Fork 77
refactor(billing): migrate wallet reload jobs to singleton policy with bulk cleanup #2422
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
Conversation
📝 WalkthroughWalkthroughThis PR removes the Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (9)
💤 Files with no reviewable changes (2)
🚧 Files skipped from review as they are similar to previous changes (3)
🧰 Additional context used📓 Path-based instructions (2)**/*.{ts,tsx,js}📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
Files:
**/*.spec.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)
Files:
🧠 Learnings (3)📓 Common learnings📚 Learning: 2025-12-29T13:20:43.626ZApplied to files:
📚 Learning: 2025-10-15T16:39:55.348ZApplied to files:
🧬 Code graph analysis (1)apps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.ts (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
🔇 Additional comments (9)
Comment |
Codecov Report❌ Patch coverage is
❌ Your patch status has failed because the patch coverage (77.77%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #2422 +/- ##
==========================================
- Coverage 51.26% 51.01% -0.25%
==========================================
Files 1069 1059 -10
Lines 29451 29089 -362
Branches 6522 6476 -46
==========================================
- Hits 15099 14841 -258
+ Misses 14116 14021 -95
+ Partials 236 227 -9
*This pull request uses carry forward flags. Click here to find out more.
🚀 New features to boost your workflow:
|
.../api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.ts
Outdated
Show resolved
Hide resolved
e106fc2 to
4c4d6f1
Compare
4c4d6f1 to
2f75d0e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.ts (1)
35-36: Update comment to reflect "none" action behavior.The comment states "Try to cancel/complete the previous job if it exists," but with the addition of
prevAction: "none", the previous job may be left untouched.🔎 Suggested comment update
- // Try to cancel/complete the previous job if it exists - // This may fail if the job is already in a terminal state, which is fine + // Handle the previous job based on prevAction: cancel it, complete it, or leave it (none) + // Cancel/complete may fail if the job is already in a terminal state, which is fineapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.ts (1)
103-103: Remove redundantstartAfter: undefinedparameter.Explicitly passing
startAfter: undefinedis redundant since undefined is the default value when the parameter is omitted.🔎 Proposed refactor
- await service.scheduleForWalletSetting(walletSetting, { prevAction: "cancel", startAfter: undefined }); + await service.scheduleForWalletSetting(walletSetting, { prevAction: "cancel" });- await service.scheduleForWalletSetting(walletSetting, { prevAction: "complete", startAfter: undefined }); + await service.scheduleForWalletSetting(walletSetting, { prevAction: "complete" });Also applies to: 128-128
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.tsapps/api/src/billing/services/wallet-settings/wallet-settings.service.spec.tsapps/api/src/billing/services/wallet-settings/wallet-settings.service.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/api/src/billing/services/wallet-settings/wallet-settings.service.spec.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
**/*.{ts,tsx,js}: Never use typeanyor cast to typeany. Always define the proper TypeScript types.
Never use deprecated methods from libraries.
Don't add unnecessary comments to the code.
Files:
apps/api/src/billing/services/wallet-settings/wallet-settings.service.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.ts
**/*.spec.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)
Don't use
jest.mock()in test files. Instead, usejest-mock-extendedto create mocks and pass mocks as dependencies to the service under testUse
setupfunction instead ofbeforeEachin test files. Thesetupfunction must be at the bottom of the rootdescribeblock, should create an object under test and return it, accept a single parameter with inline type definition, avoid shared state, and not have a specified return type.
**/*.spec.{ts,tsx}: Use<Subject>.namein the root describe suite description instead of hardcoded class/service name strings to enable automated refactoring tools to find all references
Use either a method name or a condition starting with 'when' for nested suite descriptions in tests
Use present simple, 3rd person singular for test descriptions without prepending 'should'
Files:
apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.ts
🧬 Code graph analysis (2)
apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.ts (2)
apps/api/src/billing/repositories/wallet-settings/wallet-settings.repository.ts (1)
WalletSettingOutput(19-22)apps/api/src/core/services/job-queue/job-queue.service.ts (1)
EnqueueOptions(303-303)
apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.ts (3)
apps/api/src/billing/services/wallet-settings/wallet-settings.service.ts (2)
userId(58-75)userId(77-105)apps/api/test/seeders/wallet-setting.seeder.ts (1)
generateWalletSetting(5-18)apps/api/src/billing/events/wallet-balance-reload-check.ts (1)
WalletBalanceReloadCheck(5-15)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: validate / validate-app
- GitHub Check: test-build
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.ts (2)
23-23: LGTM: Simplified validation logic.The removal of the
userIdcheck is appropriate sinceuserIdis part of the required type signaturePick<WalletSettingOutput, "id" | "userId" | "autoReloadJobId">(line 31).
45-49: LGTM: Proper handling of prevAction variants.The logic correctly handles three distinct cases:
"cancel": cancels the previous job"complete": completes the previous job"none"(or undefined): takes no action on the previous jobThis implementation aligns with the PR objective to avoid canceling jobs in certain scenarios.
apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.ts (1)
12-263: LGTM: Comprehensive test coverage following coding guidelines.The test file demonstrates:
- ✓ Proper use of
jest-mock-extendedfor mocking- ✓
setupfunction at the bottom of the root describe block- ✓
WalletReloadJobService.namein the describe suite- ✓ Method names for nested suite descriptions
- ✓ Present simple, 3rd person singular for test descriptions
- ✓ Comprehensive coverage of all public methods and edge cases
The tests thoroughly cover the new
prevAction: "none"behavior and various scheduling scenarios.
apps/api/src/billing/services/wallet-settings/wallet-settings.service.ts
Show resolved
Hide resolved
314bf27 to
c30d6d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/api/src/core/services/job-queue/job-queue.service.ts (1)
123-146: Implementation looks correct, but consider schema name handling.The raw SQL uses parameterized queries for
nameandsingletonKey, which is good. However, the schema name is directly interpolated into the query string. While it comes from configuration (not user input), consider usingpg-boss's internal escaping or quoting mechanism for the schema identifier to prevent issues if the schema name ever contains special characters.🔎 Optional: Use identifier quoting for schema name
async cancelCreatedBy(query: { name: string; singletonKey: string }): Promise<void> { const db = await this.pgBoss.getDb(); const schema = this.coreConfig.get("POSTGRES_BACKGROUND_JOBS_SCHEMA"); + const escapedSchema = `"${schema.replace(/"/g, '""')}"`; const result = (await db.executeSql( ` WITH results as ( - UPDATE ${schema}.job + UPDATE ${escapedSchema}.job SET completed_on = now(), state = 'cancelled' WHERE name = $1 AND state = 'created' AND singleton_key = $2 RETURNING id ) SELECT id FROM results `, [query.name, query.singletonKey] )) as { rows: { id: string }[] }; this.logger.info({ event: "JOBS_CANCELLED", jobIds: result.rows.map(r => r.id) }); }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
apps/api/drizzle/0024_overjoyed_swarm.sqlapps/api/drizzle/meta/0024_snapshot.jsonapps/api/drizzle/meta/_journal.jsonapps/api/src/billing/model-schemas/wallet-setting/wallet-setting.schema.tsapps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.spec.tsapps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.tsapps/api/src/billing/services/wallet-settings/wallet-settings.service.spec.tsapps/api/src/billing/services/wallet-settings/wallet-settings.service.tsapps/api/src/core/services/job-queue/job-queue.service.tsapps/api/test/seeders/wallet-setting.seeder.ts
💤 Files with no reviewable changes (2)
- apps/api/src/billing/model-schemas/wallet-setting/wallet-setting.schema.ts
- apps/api/test/seeders/wallet-setting.seeder.ts
✅ Files skipped from review due to trivial changes (2)
- apps/api/drizzle/meta/0024_snapshot.json
- apps/api/drizzle/0024_overjoyed_swarm.sql
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/api/src/billing/services/wallet-settings/wallet-settings.service.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursor/rules/general.mdc)
**/*.{ts,tsx,js}: Never use typeanyor cast to typeany. Always define the proper TypeScript types.
Never use deprecated methods from libraries.
Don't add unnecessary comments to the code.
Files:
apps/api/src/billing/services/wallet-settings/wallet-settings.service.spec.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.tsapps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.tsapps/api/src/core/services/job-queue/job-queue.service.tsapps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.spec.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.ts
**/*.spec.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)
Don't use
jest.mock()in test files. Instead, usejest-mock-extendedto create mocks and pass mocks as dependencies to the service under testUse
setupfunction instead ofbeforeEachin test files. Thesetupfunction must be at the bottom of the rootdescribeblock, should create an object under test and return it, accept a single parameter with inline type definition, avoid shared state, and not have a specified return type.
**/*.spec.{ts,tsx}: Use<Subject>.namein the root describe suite description instead of hardcoded class/service name strings to enable automated refactoring tools to find all references
Use either a method name or a condition starting with 'when' for nested suite descriptions in tests
Use present simple, 3rd person singular for test descriptions without prepending 'should'
Files:
apps/api/src/billing/services/wallet-settings/wallet-settings.service.spec.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.tsapps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.spec.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: ygrishajev
Repo: akash-network/console PR: 2422
File: apps/api/src/billing/services/wallet-settings/wallet-settings.service.ts:124-128
Timestamp: 2025-12-29T13:20:36.482Z
Learning: In the wallet-settings service (apps/api/src/billing/services/wallet-settings/wallet-settings.service.ts), auto-reload jobs are not eagerly canceled when autoReloadEnabled is disabled. Instead, jobs check the autoReloadEnabled flag at execution time and complete early if disabled. This design avoids concurrency issues that could occur with eager cancellation.
📚 Learning: 2025-12-29T13:20:36.482Z
Learnt from: ygrishajev
Repo: akash-network/console PR: 2422
File: apps/api/src/billing/services/wallet-settings/wallet-settings.service.ts:124-128
Timestamp: 2025-12-29T13:20:36.482Z
Learning: In the wallet-settings service (apps/api/src/billing/services/wallet-settings/wallet-settings.service.ts), auto-reload jobs are not eagerly canceled when autoReloadEnabled is disabled. Instead, jobs check the autoReloadEnabled flag at execution time and complete early if disabled. This design avoids concurrency issues that could occur with eager cancellation.
Applied to files:
apps/api/src/billing/services/wallet-settings/wallet-settings.service.spec.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.tsapps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.tsapps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.spec.tsapps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.ts
📚 Learning: 2025-10-15T16:39:55.348Z
Learnt from: jzsfkzm
Repo: akash-network/console PR: 2039
File: apps/deploy-web/tests/ui/change-wallets.spec.ts:4-10
Timestamp: 2025-10-15T16:39:55.348Z
Learning: In the Akash Console E2E tests using the context-with-extension fixture, the first wallet is automatically created during fixture setup via `importWalletToLeap` in `apps/deploy-web/tests/ui/fixture/wallet-setup.ts`, so tests that call `frontPage.createWallet()` are creating a second wallet to test wallet switching functionality.
Applied to files:
apps/api/src/billing/services/wallet-settings/wallet-settings.service.spec.ts
🧬 Code graph analysis (2)
apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.ts (2)
apps/api/test/seeders/wallet-setting.seeder.ts (1)
generateWalletSetting(5-17)apps/api/src/billing/events/wallet-balance-reload-check.ts (1)
WalletBalanceReloadCheck(5-15)
apps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.ts (1)
apps/api/src/billing/repositories/wallet-settings/wallet-settings.repository.ts (1)
WalletSettingOutput(19-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: validate / validate-app
- GitHub Check: test-build
🔇 Additional comments (17)
apps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.spec.ts (2)
52-64: LGTM!The test correctly verifies the updated scheduling API with
withCleanup: true, aligning with the handler implementation changes.
185-194: LGTM!Test assertion correctly updated to expect
withCleanup: trueoption when scheduling the next check.apps/api/drizzle/meta/_journal.json (1)
172-179: LGTM!Migration journal entry correctly added for the
auto_reload_job_idcolumn removal with proper sequencing.apps/api/src/billing/services/wallet-balance-reload-check/wallet-balance-reload-check.handler.ts (3)
24-24: LGTM!Type correctly simplified to only require
idanduserIdafter removingautoReloadJobIdfrom the schema.
41-41: Policy change to "singleton" is appropriate.The singleton policy ensures only one job instance per singleton key can be active, which aligns with the cleanup-based approach where prior jobs are cancelled before scheduling new ones.
207-217: LGTM!The
withCleanup: trueflag correctly triggers cancellation of previously created jobs before scheduling the next check, replacing the previousprevActionapproach. Based on learnings, jobs checkautoReloadEnabledat execution time, so this cleanup approach avoids concurrency issues.apps/api/src/billing/services/wallet-settings/wallet-settings.service.spec.ts (4)
54-57: LGTM!Test correctly expects the full
updatedSettingobject now thatautoReloadJobIdis removed from the schema.
82-87: LGTM!Assertion correctly simplified to only expect
idanduserIdin the wallet setting passed toscheduleForWalletSetting.
192-194: LGTM!Mock setup correctly reflects that
cancelis no longer needed, as cancellation now happens lazily at job execution time. Based on learnings, this design avoids concurrency issues.
201-201: LGTM!Simplification is correct -
publicSettingnow equalswalletSettingsinceautoReloadJobIdwas removed from the schema.apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.spec.ts (4)
12-55: LGTM!Tests for
scheduleImmediateproperly cover the early return scenarios (no wallet setting, auto-reload disabled) and the happy path. Test follows coding guidelines with proper mock usage and descriptive test names.
57-158: LGTM!Comprehensive test coverage for
scheduleForWalletSettingincluding:
- Basic scheduling without cleanup
- Cancellation flow with
withCleanup: truestartAfteroption handling- Combined options
- Error handling when job creation fails
Tests correctly verify the new API contract.
160-172: LGTM!Test correctly verifies
cancelCreatedByUserIdcallsjobQueueService.cancelCreatedBywith the appropriate name and singleton key.
174-188: LGTM!Setup function follows coding guidelines: positioned at the bottom of the describe block, creates the service under test, returns all necessary mocks, and avoids shared state.
apps/api/src/billing/services/wallet-reload-job/wallet-reload-job.service.ts (3)
18-24: LGTM!The
scheduleImmediatemethod is correctly simplified. It only schedules when the wallet setting exists andautoReloadEnabledis true, which is the expected behavior.
26-48: LGTM!The
scheduleForWalletSettingimplementation correctly:
- Optionally cancels previous jobs when
withCleanupis true- Creates a new job with a consistent singleton key
- Logs and throws on job creation failure
The singleton key format
${WalletBalanceReloadCheck.name}.${userId}is consistent with usage in the tests and handler.
50-52: LGTM!The
cancelCreatedByUserIdhelper provides a clean API for cancelling jobs by user ID, using the same singleton key pattern.
|
@coderabbitai can you construct a diagram how the feature would work now |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 14814 @ygrishajev Here's a comprehensive diagram showing how the auto-reload feature works after your changes: sequenceDiagram
participant User
participant WalletSettingService
participant WalletReloadJobService
participant JobQueueService
participant WalletBalanceReloadCheckHandler
participant StripeService
Note over User,StripeService: Flow 1: Enabling Auto-Reload
User->>WalletSettingService: upsertWalletSetting({autoReloadEnabled: true})
WalletSettingService->>WalletSettingService: #validate (check payment method exists)
WalletSettingService->>WalletSettingService: #arrangeSchedule(prev, next)
alt prev.autoReloadEnabled == false && next.autoReloadEnabled == true
WalletSettingService->>WalletReloadJobService: scheduleForWalletSetting(next)
WalletReloadJobService->>JobQueueService: enqueue(WalletBalanceReloadCheck)
Note right of JobQueueService: singletonKey: WalletBalanceReloadCheck.${userId}
JobQueueService-->>WalletReloadJobService: jobId
WalletReloadJobService-->>WalletSettingService: jobId
end
WalletSettingService-->>User: WalletSettingOutput (no autoReloadJobId)
Note over User,StripeService: Flow 2: Job Execution & Recurring Checks
JobQueueService->>WalletBalanceReloadCheckHandler: handle(payload, job)
Note right of WalletBalanceReloadCheckHandler: policy: "singleton"
WalletBalanceReloadCheckHandler->>WalletBalanceReloadCheckHandler: #collectResources(payload)
WalletBalanceReloadCheckHandler->>WalletBalanceReloadCheckHandler: Check autoReloadEnabled at runtime
alt autoReloadEnabled == false
WalletBalanceReloadCheckHandler-->>JobQueueService: Exit early (validation error)
else autoReloadEnabled == true
WalletBalanceReloadCheckHandler->>WalletBalanceReloadCheckHandler: #tryToReload(resources)
alt balance < threshold
WalletBalanceReloadCheckHandler->>StripeService: createPaymentIntent(amount)
StripeService-->>WalletBalanceReloadCheckHandler: Payment created
else balance >= threshold
Note right of WalletBalanceReloadCheckHandler: Skip reload (sufficient balance)
end
WalletBalanceReloadCheckHandler->>WalletBalanceReloadCheckHandler: #scheduleNextCheck(resources)
WalletBalanceReloadCheckHandler->>WalletReloadJobService: scheduleForWalletSetting(walletSetting, {withCleanup: true, startAfter: +24h})
alt withCleanup == true
WalletReloadJobService->>WalletReloadJobService: cancelCreatedByUserId(userId)
WalletReloadJobService->>JobQueueService: cancelCreatedBy({name, singletonKey})
Note right of JobQueueService: Cancels "created" jobs<br/>matching singleton key
JobQueueService-->>WalletReloadJobService: void
end
WalletReloadJobService->>JobQueueService: enqueue(WalletBalanceReloadCheck, {singletonKey, startAfter})
JobQueueService-->>WalletReloadJobService: new jobId
WalletReloadJobService-->>WalletBalanceReloadCheckHandler: new jobId
end
Note over User,StripeService: Flow 3: Disabling Auto-Reload
User->>WalletSettingService: upsertWalletSetting({autoReloadEnabled: false})
WalletSettingService->>WalletSettingService: Update setting in DB
WalletSettingService-->>User: Updated setting
Note over JobQueueService,WalletBalanceReloadCheckHandler: Existing jobs NOT eagerly canceled
JobQueueService->>WalletBalanceReloadCheckHandler: handle(payload, job)
WalletBalanceReloadCheckHandler->>WalletBalanceReloadCheckHandler: Check autoReloadEnabled (now false)
WalletBalanceReloadCheckHandler-->>JobQueueService: Exit early, no more jobs scheduled
Key Changes Illustrated:
This design is cleaner and avoids race conditions that could occur with eager cancellation while still preventing job accumulation through the cleanup mechanism. 🧠 Learnings used |
be7bee4 to
2b9ebd7
Compare
…h bulk cleanup Change wallet balance reload check job management from tracking job IDs in the database to using pg-boss singleton policy with bulk cleanup. Key changes: - Change handler policy from "short" to "singleton" to allow multiple scheduled jobs while maintaining single active execution - Remove autoReloadJobId field from wallet-setting schema - Remove job cancellation from wallet-settings service delete operation - Add cancelCreatedBy method to JobQueueService for bulk cancellation of created jobs by singletonKey - Update handler to use withCleanup flag when scheduling next check - Simplify WalletReloadJobService by removing transaction wrapper and job ID tracking This approach allows multiple scheduled jobs to exist while ensuring only one active job runs at a time, with cleanup handled in bulk rather than tracking individual job IDs. Fixes race condition where REST handlers updating wallet settings could mark an active job as cancelled even though it completes successfully, causing state inconsistencies. refs #1779
6cf228c to
8f837b8
Compare
Change wallet balance reload check job management from tracking job IDs
in the database to using pg-boss singleton policy with bulk cleanup.
Key changes:
scheduled jobs while maintaining single active execution
of created jobs by singletonKey
job ID tracking
This approach allows multiple scheduled jobs to exist while ensuring
only one active job runs at a time, with cleanup handled in bulk
rather than tracking individual job IDs.
Fixes race condition where REST handlers updating wallet settings could
mark an active job as cancelled even though it completes successfully,
causing state inconsistencies.
refs #1779
Summary by CodeRabbit
Bug Fixes
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.