Scheduled jobs reference
All 93 jobs the scheduler registers — exact name, cadence, which extension gates it, what stops when it stops, the eleven that survive a disable, and a symptom-to-job lookup for stuck withdrawals, uncredited deposits and stale prices.
The cron process runs 93 job definitions. Processes and ports
describes the process; this page describes the work.
The registry is built in backend/src/cron/index.ts. Every entry carries a name
(the key the admin panel and the trigger endpoint use), a period and a
function. period is a fixed interval in milliseconds, not a crontab
expression. There is no 0 3 * * * anywhere in this platform: a job with a
24-hour period fires 24 hours after the scheduler started it, not at midnight, so
a restart moves every daily job to a new hour of the day. Nothing in the admin
panel or .env changes a period — it is a constant in the source.
22 jobs run on every install. The remaining 71 are grouped into 18 extension buckets and are absent from the registry when that extension is off — with eleven exceptions that keep running because they settle money customers are already owed, listed under Jobs that survive a disable. A short list on the cron console is not a fault; it is an install with few addons.
The 22 core jobs
These are registered regardless of which addons you own. category is normal
for all of them.
| Job | Every | What stops if it does not run |
|---|---|---|
processPendingOrders |
15s | Binary orders whose in-process expiry timer was lost (deploy, crash) never settle. This is the backstop, and the tight cadence is deliberate — a slow settle is indistinguishable from a deliberate refusal in the audit trail. |
evaluatePriceAlerts |
30s | Price alerts fire only in a browser tab left open on that market. An armed alert stops following the user to another device and stops firing overnight, which is the only time anyone wants one. Costs nothing when nobody has one armed. |
processPendingSpotOrders |
60s | Open spot orders are never reconciled against the exchange: fills are not credited, cancellations are not refunded, partial fills hang. |
processCurrenciesPrices |
2m | Every currency price in the database freezes at its last value. Anything that converts to USD — wallet totals, fee figures, dashboards — drifts silently. |
reconcileSpotWithdrawals |
5m | A spot withdrawal whose exchange payout committed but whose local status write was lost to a restart stays PROCESSING forever. Idempotent; short cadence so crash-orphaned rows surface fast. |
reconcileTransfiDeposits |
5m | TransFi deposits stop crediting when a webhook is lost. fund_processing is emitted by no webhook and TransFi stops retrying after roughly two hours, so this is required, not optional. |
reconcileTransfiPayouts |
5m | A dispatched TransFi payout is never settled or failed when its webhook is lost, and a row orphaned between debit and dispatch is never resolved — the customer waits that long for a refund. |
poolBackingSettle |
5m | In-flight pool-backing settlements are never verified against the receiving side's own evidence, and in auto mode no netted movement is dispatched, so the exchange pool stays short of what it owes. In off, monitor and manual it settles nothing by design. See Pool backing. |
processSpotPendingDeposits |
15m | Pending spot wallet deposits are not processed. |
poolBackingReconcile |
15m | No currency's Spot liabilities are measured against the exchange's holdings, so the gap is never computed, the residual is never explained and drift is never recorded. Moves no money. |
processExpiredUserBlocks |
15m | A temporarily blocked user is never unblocked. The block has an expiry date; nothing else acts on it. |
syncMarketNews |
15m | The trading terminal's news feed stops refreshing. Quiet no-op with no provider key configured — operator-authored stories still serve. |
fetchFiatCurrencyPrices |
30m | Fiat rates freeze. Every fiat-denominated conversion keeps using the last figure fetched. |
processPendingWithdrawals |
30m | Pending spot wallet withdrawals are never picked up. |
processGeneralInvestments |
1h | General investment plans never mature: no settlement, no profit, no principal returned. |
ledgerArchive |
1h | Nothing, until ECO_LEDGER_ARCHIVE_ENABLED=true: then old, finished transaction rows and their audit rows stop moving into the archive tables and the live ledger keeps growing. Off, it returns before it opens the database. See Backup and restore. |
cacheExchangeCurrencies |
1h | Warms the Redis exchangeCurrencies blob the currency endpoints read. See the note below — this one is less load-bearing than it looks. |
licenseHeartbeat |
6h | The licence server is not told this install is alive. |
processWalletPnl |
24h | No wallet PnL snapshot is written, so 24-hour change figures stop moving. |
cleanupOldPnlRecords |
24h | Old PnL rows and zero-balance rows accumulate. |
purgeGeoAccessLog |
24h | The geographic access log grows without bound. Does nothing when retention is set to keep entries indefinitely. |
poolBackingAttribute |
24h | The Spot balances the platform minted itself — investment and AI returns, fixed-rate staking rewards, referral rewards, binary outcomes, commerce, platform fees — stop being written as minted obligation rows per day, so the reconciliation's residual goes back to being an unexplained number. The same run writes the exchange_fee rows read from the exchange's own trade history. |
The job writes the exchangeCurrencies Redis key with a 120-second TTL, on an
hourly period, so the key is expired for most of the hour. That is not a bug: the
blob carries price, which processCurrenciesPrices rewrites every two minutes,
and a longer TTL would let the cached price disagree with the row by up to fifteen
ticks. GET /api/exchange/currency falls back to the database on a miss and never
re-populates the key itself.
The practical consequence: this job stopping does not break the currency list. A currency you enable appears within two minutes either way.
The 71 addon jobs
Each block registers only when the named extension is enabled on
Admin → System → Extensions. Toggling an extension does not need a restart —
the scheduler re-evaluates gating every 60 seconds and logs
Extension <name> enabled — scheduled cron <job> or
Extension <name> disabled — stopped cron <job>.
ecosystem — 5 jobs
| Job | Every | Owns |
|---|---|---|
verifyPendingEcoDeposits |
60s | Finalises pending on-chain deposits held in Redis: confirmation-depth checks and crediting. The only path that does this. |
backgroundDepositScanner |
60s | Detects deposits that arrive after the customer closes the deposit page. Scans recently-active addresses only, with a per-chain token bucket. Disable with ECOSYSTEM_BACKGROUND_SCAN=false. |
btcDepositScanner |
60s | Scans BTC wallets through the provider chain chosen by BTC_NODE (node, mempool or blockcypher; defaults to mempool with fallback). |
ecosystemWithdrawRecon |
5m | Re-enqueues orphaned PENDING ecosystem withdrawals whose rows outlived the in-memory queue — the wallet is already debited, so without this the money is gone and the payout never happens. |
processPendingEcoWithdrawals |
30m | The same recovery sweep on a longer cadence, kept as a second safety net. |
futures — 5 jobs
| Job | Every | Owns |
|---|---|---|
sweepFuturesPositions |
60s | Safety net that re-marks open positions against the live ticker, enforcing stop-loss, take-profit and liquidation. The matching engine already sweeps every 2 seconds where it holds the lease; this catches a realm whose engine never booted. |
settleFuturesFunding |
60s | Charges and pays funding on open perpetual positions at each funding window, collecting from payers first and distributing only what was collected. Only a market with an operator-set funding rate is funded, and no market has one by default — with none configured the job settles nothing. It acts only on a window boundary; the tight cadence is what makes a charge land in the hour it belongs to after a restart. |
reconcileFuturesPositions |
5m | Replays ScyllaDB status writes for positions whose wallet credit committed but whose Scylla write failed. |
reconcileFuturesOrders |
5m | The same, for orders. |
sweepFuturesFeeReversals |
5m | A cancel that died between recording the fee it owes back and booking it leaves the treasury reporting a refunded fee as revenue. It verifies the trader's refund actually reached a wallet before touching the treasury, so an unpaid refund is abandoned rather than booked as a loss. A healthy install settles nothing here — the cancel books it inline — so this only acts after a process died mid-cancel. |
forex_trading — 6 jobs
| Job | Every | Owns |
|---|---|---|
runFxExecutionReconciler |
60s | A-book correctness backstop: replays each enabled execution provider's broker ledger, detects orphans both ways, auto-suspends NEW routing on a cursor stall. Silent no-op with no provider rows. |
runFxHedgeMonitor |
60s | Syncs each enabled provider's balance / NAV / margin / closeout onto the provider row and alerts on a margin breach. |
reconcileFxAccounts |
5m | Expires due GTD/DAY orders, verifies the deals ledger (Σ pnl == balance) for accounts with open positions, refreshes denormalised equity and margin. |
processFxAffiliateRebates |
10m | Awards IB/partner rebates on committed commission deals. LIVE accounts only. |
syncFxCalendarAndNews |
15m | Refreshes the economic calendar and news from the active fx data provider. Operator-authored (MANUAL) rows are never touched. |
processFxSwaps |
1h | Settles overnight swap at the 17:00 New York cutoff. Hourly on purpose — every tick settles the most recent elapsed cutoff plus any earlier ones still inside the backfill window. A daily period would land at an arbitrary hour and a restart past a cutoff would lose that day's rollover, uncharged. |
dex — 5 jobs
| Job | Every | Owns |
|---|---|---|
dexConfirmationSweep |
30s | Polls receipts for PENDING/MINED swaps, advances the swap state machine, and re-verifies each CONFIRMED row once inside its reorg window. Declines on a dedicated cron process, where the web half already holds the dex-confirmations lease and sweeps — so exactly one process polls the chain whichever way the deployment is split. |
runDexMarketRefresh |
5m | Refreshes cached ticker and liquidity figures for every enabled pair from the configured market-data provider. Read-only: a provider outage costs the pair list its freshness and nothing else. |
dexFeeSweepSettle |
5m | Credits fee accruals the operator has already swept on-chain, once the recorded sweep transaction reaches the chain's confirmation depth, and books one adminProfit row of type DEX_SWAP per real transfer. Nothing books DEX revenue without it. |
dexQuotePrune |
1h | Deletes dex_quote rows past dexQuoteRetentionDays, default 90 days; the settings console floors it at 1 and refuses 0, so the job's keep-everything branch is not reachable from the UI. Quotes a dexSwap row references are kept whatever their age, because trade history joins through them. Bounded at 1,000 rows a slice and 50 slices a run. dex_quote takes a row on every quote and the terminal re-quotes on a timer while a user simply watches the screen, so this is the fastest-growing table in the addon. |
dexTokenRescreen |
24h | Re-runs the safety screen over the token catalogue, oldest first, dexScreeningSliceSize rows a run, on a keyset cursor so dead contracts cannot starve the queue behind them. Records verdicts only — it never changes a token's listing or status. |
These are gated on the dex extension. Earlier builds defined the four
older jobs inside the forex_trading block, so an operator who disabled Forex
Trading stopped the confirmation sweep and the fee settlement with it, silently.
If you are working from an older runbook, forex_trading is no longer the
toggle to check here.
copy_trading — 8 jobs
| Job | Every | Owns |
|---|---|---|
processPendingCopyTrades |
10s | Replicates leader trades to active followers. |
processClosedCopyTrades |
30s | Processes closed trades and distributes profit shares. |
monitorCopyTradingStopLevels |
30s | Triggers stop-loss and take-profit on open follower trades. |
checkCopyTradingDailyLossLimits |
60s | Pauses followers who exceed their daily loss limit. |
reconcileCopyTradingOrders |
5m | Releases COPY_TRADING wallet holds stranded by an order cancelled out of band. |
updateCopyTradingLeaderDailyStats |
5m | Daily statistics for active leaders. |
resetCopyTradingDailyLimits |
24h | Resets daily limits and reactivates paused followers. |
aggregateCopyTradingWeeklyAnalytics |
7d | Weekly leader performance analytics. |
ai_market_maker — 7 jobs
| Job | Every | Owns |
|---|---|---|
processAiMarketMakerEngine |
5s | The engine loop. Runs in whichever process holds the ecosystem matching lease; on a dedicated cron process it is a structural no-op by design. |
processAiRiskMonitor |
10s | Volatility, loss limits and trading-pattern risk metrics. |
processAiPriceSync |
30s | External price feeds, and alerts on a major deviation. |
processAiAnalyticsAggregator |
15m | Trading statistics and performance metrics. |
processAiPoolRebalancer |
1h | Rebalances pools when asset ratios skew. |
processAiDailyReset |
24h | Resets daily volume and trade counters, writes the daily summary. |
processAiHistoryRetention |
24h | Prunes per-trade history past the retention window. Daily summaries and lifecycle audit rows are never pruned. |
ai_support — 8 jobs
| Job | Every | Owns |
|---|---|---|
aiSupportCacheHealthCheck |
1h | Alerts when prompt-cache reads fall below half of input tokens. Prompt-cache invalidation multiplies the bill with no error and no log line, so this alarm is the only detection that exists. |
aiSupportExpireStale |
1h | Closes off actions and step-by-step processes nobody used in time. Always on, whatever your auto-close setting. |
aiSupportProactiveSweep |
15m | Opens a ticket for deposits and withdrawals that failed in the last 45 minutes. Does nothing unless Proactive Support is switched on. |
aiSupportReindexKnowledge |
24h | Re-chunks the shipped documentation packs, your knowledge base and the FAQ. Skips packs whose checksum has not changed. |
aiSupportRetentionSweep |
24h | Deletes AI turn records past the retention window (default 90 days). |
aiSupportHarvestAnswers |
24h | Files a DRAFT article from the reply a human agent already typed. Makes no model call. |
aiSupportAutoCloseResolved |
24h | Closes tickets your team answered and the customer never replied to. Ships at zero days, which is off. |
aiSupportShareQuestions |
7d | Sends anonymised question fingerprints to MashDiv. Off unless you switch it on. |
trading_bot — 5 jobs
| Job | Every | Owns |
|---|---|---|
processTradingBotEngine |
5s | Supervises the engine: starts it, stops it in maintenance mode, resyncs running bots. |
checkTradingBotStaleBots |
60s | Marks RUNNING bots whose engine tick went stale as errored and notifies their owners. |
updateTradingBotStrategyRatings |
1h | Aggregates review ratings for public approved strategies. |
aggregateTradingBotDailyStats |
24h | Daily per-bot statistics and resets the daily trade/profit counters — the daily loss limit depends on this reset. |
cleanupTradingBotOldData |
7d | Prunes audit logs and stale cancelled/failed orders past 90 days. |
gateway — 3 jobs
| Job | Every | Owns |
|---|---|---|
processGatewayWebhookRetries |
60s | Redelivers failed merchant webhooks on a 1m / 5m / 30m / 2h / 24h backoff. |
processGatewayPaymentExpiry |
5m | Marks lapsed checkout sessions EXPIRED and emits payment.expired. |
processGatewayPayouts |
1h | Creates merchant payout records. INSTANT and DAILY balances are candidates every run, so an INSTANT merchant settles within this hourly cadence — not immediately — and still awaits admin approval. |
nft — 3 jobs
| Job | Every | Owns |
|---|---|---|
expireOffers |
5m | Expires NFT offers past their expiration date. |
settleAuctions |
10m | Settles ended auctions. |
processNFTBackups |
15m | Runs due blockchain-state backups. The finest schedule the admin route offers is hourly, so 15m keeps a backup close to its declared nextRun. |
p2p — 2 jobs
| Job | Every | Owns |
|---|---|---|
p2pTradeTimeout |
1m | Expires trades past their expiration date and releases the escrowed funds. |
updateP2PReputationScores |
1h | Recalculates reputation for users with recent activity, records milestones. |
ico — 2 jobs
| Job | Every | Owns |
|---|---|---|
processIcoOfferings |
1h | Advances offering phases and status. |
processIcoVestingReleases |
1h | Announces due vesting tranches, closes finished schedules, cancels schedules behind refunded contributions. |
staking — 7 jobs
One extension carries two products. processStakingPositions belongs to the
fixed-rate product; the other six run on-chain staking, and the registry does
not separate them — which product a pool and a position settle under is the
stakingMode setting and the row's own snapshot, not the job list. See
How a stake moves.
| Job | On screen | Every | Owns |
|---|---|---|---|
processStakingPositions |
Process Staking Logs | 1h | Fixed-rate only. Matures positions, pays the published rate and returns principal. Survives a disable. |
processRealStakingBatches |
On-chain staking: batches | 2m | Signs and broadcasts every due on-chain batch — gathers, delegations, exits, claims, returns, refunds — and polls the ones in flight. Exits run regardless of the intake switches. Stopped, no coin moves in either direction: nothing is delegated and nothing unbonded is returned. Survives a disable. |
observeRealStaking |
On-chain staking: observe rewards | 15m | Reads what the network paid each on-chain pool for a new epoch or day, moves the share price, mints the operator's commission as treasury shares and writes one earning row per holder. Stopped, a reward the network really paid never reaches a holder's share value. |
reconcileRealStaking |
On-chain staking: reconcile | 1h | Compares the chain against the book — wallet gas reserve, share ledger, tranche value, stuck batches, observer lag, validator policy — and opens and clears incidents. Never moves coins. It is also the only thing that raises LOW_GAS, and it does so only where the wallet's gas reserve floor is above zero. |
refreshStakingValidatorSets |
On-chain staking: validator policy | 6h | Re-screens every validator set against the live network and the policy; a breaching validator receives no new delegation. Stopped, new delegations keep going to a validator that has since breached. |
alertRealStaking |
On-chain staking: alerts | 10m | The time-based incidents the reconciler cannot see from the chain: exits past the promised bound, stakes still pending delegation, and a settled commission exit that is not being paid. |
generateRealStakingStatements |
On-chain staking: monthly statements | 24h | Writes the previous month's statement for every user who held an on-chain position in it — staked, exited, rewards net of commission, commission, value at statement time. Each run only ever writes the month before today, so the daily cadence is repeated attempts at one statement rather than a statement a day, and a statement is generated once per user and month and never regenerated. |
Six of the seven load from one module. When that import fails they all refuse together — see A cron module that fails to load, which is the shape this failure was first observed in.
One-job extensions
| Extension | Job | Every | Owns |
|---|---|---|---|
ai_investment |
processAiInvestments |
1h | Settles active AI investments. |
forex |
processForexInvestments |
1h | Settles active Forex investments. |
mlm |
processMlmReferralConditions |
1h | Evaluates referral conditions and creates rewards. |
mailwizard |
processMailwizardCampaigns |
1h | Sends campaign email. Each run sends at most speed messages per active campaign — speed is a per-run budget and a run happens once an hour. |
binary_ai_engine |
processBinaryAiEngine |
10s | Boots and reloads active engines after a restart, reconciles DB against memory, enforces the global kill-switch. |
Jobs that survive a disable
Disabling an extension stops its jobs within the minute — with eleven exceptions. A job that settles money the platform already owes is scheduled on the disabled branch, and scheduled again after a restart:
processPendingEcoWithdrawals, ecosystemWithdrawRecon, processAiInvestments,
runFxExecutionReconciler, processIcoOfferings, processStakingPositions,
processRealStakingBatches, p2pTradeTimeout, expireOffers,
processClosedCopyTrades, reconcileCopyTradingOrders.
The addon's routes still close, so nothing new can start. Two consequences for
this page: a disabled addon can still show rows on the cron console and that is
correct, and switching an addon off is not a way to stop one of these eleven.
The only way is stopEverything on the extension toggle, which records the addon
in the cronHardStoppedExtensions setting and brings them down with the rest. If
that setting cannot be read, the jobs keep running — the list fails open towards
the people who are owed.
Why each of the eleven is on the list, and what stopped being settled before they were, is in Bicrypto 6.7.6.
"No error in the log" is not evidence a job ran
A job may refuse itself on the process it is registered in and still return
normally. backend/src/cron/refusal.ts is the only sanctioned way for that to
happen, and it is never quiet: every refusal lands in four places at once — sticky
state on the job row, logger.error, the live log on the cron console, and an
URGENT in-app plus email alert to every Admin and Super Admin.
The state is recorded on every refused tick. The three announcements are rate-limited to one per job per fifteen minutes, because the jobs that refuse tick every 5 to 60 seconds.
A refusal carries four fields, and the alert prints all four:
| Field | Means |
|---|---|
job |
The registry name, so you can find it on the console. |
reason |
Why this process must not run it. |
impact |
What is consequently not happening, in operator terms. |
fix |
The concrete change — an extension to enable, a setting to move. |
There is also a degraded variant. It means "running, but achieving nothing",
not "not running": the handler executed and no tick was dropped, but its work has
nowhere to land. The console shows those in warning colour rather than
destructive, and the job's status stays reportable rather than refused.
A cron module that fails to load
The three gates below are about which process a job is in. There is a fourth producer of a refusal that is not: every addon job reaches its handler through a dynamic import, and an import can fail on an install that owns the addon.
safeImportModule returns the same null for "the customer never bought this
addon" and for "the addon is installed and its module threw on import". Collapsed
that way, a broken import made the wrapper return without throwing,
lastRunError stayed null, and the admin table showed the job completed with
a 100% success rate. It was observed on a live install, with all six on-chain
staking jobs reading green while the module had never loaded once:
CRON [IMPORT] Failed to load module @b/api/(ext)/staking/utils/real/cron:
Cannot find module '.../backend/dist/src/blockchains/network-fee-tracker'addonCronModule in backend/src/cron/index.ts now separates the two. An absent
addon stays silent — a customer who did not buy staking is not suffering a fault.
An addon that is on disk and did not load gets a standing refusal on every job
behind that module, so those rows read REFUSED rather than completed, and the
reason carries the loader's own message verbatim.
The alert is keyed on the module rather than the job, because AI Support and copy trading each put eight jobs behind one import, the AI market maker seven and on-chain staking six — keyed per job, one failed import would mail every administrator eight identical URGENT alerts every fifteen minutes. The per-job refusal state is not keyed that way, so every affected row still shows its own refusal on the console.
There is nothing to change in the deployment shape here; the fix is in the
reason. A missing dependency usually means an addon built against a newer core
than the one installed. A syntax error or a throw during module init is a defect
in that addon's build. Restart the scheduler once the module loads.
The three refusal gates
backend/src/cron/mode.ts holds the three runtime tests. All three answer false
immediately on a single-process (CRON_MODE=inline) install — none of them can
fire there.
fxVenueCronsWouldDuplicate() — refuses runFxExecutionReconciler and runFxHedgeMonitor
When. On a dedicated cron process, whenever any fxExecutionProvider row has
status: true, or any fx order is EXTERNAL/ROUTING, or any fx position is
EXTERNAL/OPEN.
Why. Those two jobs drive the broker connection, not the quote feed. Two
reconcilers over one broker account replay the same fills and rewrite
syncCursor/externalMeta whole-column from two writers. No restart undoes that.
What you change. Nothing — and this one is deliberately not alerted, only
logged at debug level. armFxVenueSupervisor arms both on the process that holds
the forex-trading lease at the same 60-second cadence, so the work is demonstrably
being done elsewhere. It fails closed: if the check itself cannot answer, the jobs
stay refused.
aiMarketMakerHasNoEngineHost() — degrades processAiMarketMakerEngine
When. ai_market_maker is enabled and ecosystem is not.
Why. The market maker trades ecosystem markets, and its bots enqueue into the
matcher's in-memory queue. With ecosystem off, nothing anywhere boots a matcher,
so there is nothing to quote. This is not about which process cron runs in — the
combination cannot make markets on any deployment shape.
What you change. Enable the ecosystem extension, or disable
ai_market_maker. The other six AI market maker jobs are unaffected and keep
running.
tradingBotHasNoEngineHost() — degrades processTradingBotEngine
When. trading_bot is enabled and ecosystem is not.
Why. The same shape. Bots trade ecosystem markets and price off ecosystem candles, so even a paper bot has no price feed without it.
What you change. Enable the ecosystem extension, or disable trading_bot.
Strategy ratings, daily stats and weekly cleanup are unaffected and keep running.
Symptom to job
| Symptom | Look at | Every |
|---|---|---|
| A spot withdrawal is stuck at PENDING | processPendingWithdrawals |
30m |
| A spot withdrawal is stuck at PROCESSING with no transaction id | reconcileSpotWithdrawals |
5m |
| An ecosystem (on-chain) withdrawal never leaves | ecosystemWithdrawRecon, then processPendingEcoWithdrawals |
5m / 30m |
| A confirmed on-chain deposit is not credited | verifyPendingEcoDeposits |
60s |
| A deposit arrived after the customer closed the page | backgroundDepositScanner (or btcDepositScanner for BTC) |
60s |
| A card/bank deposit through TransFi is not credited | reconcileTransfiDeposits |
5m |
| A fiat rate is stale | fetchFiatCurrencyPrices |
30m |
| A crypto price is stale | processCurrenciesPrices |
2m |
| A blocked user is still blocked past their expiry | processExpiredUserBlocks |
15m |
| An investment matured but never paid out | processGeneralInvestments (or processAiInvestments / processForexInvestments for those addons) |
1h |
| A fixed-rate staking position matured but never paid out | processStakingPositions |
1h |
An on-chain stake is stuck at PENDING_DELEGATION, or an exit finished unbonding and nothing arrived |
processRealStakingBatches |
2m |
| An on-chain pool's share price has not moved for a full epoch | observeRealStaking |
15m |
| A binary order expired but never settled | processPendingOrders |
15s |
| A P2P trade passed its deadline and escrow is still held | p2pTradeTimeout |
1m |
| A merchant webhook was never redelivered | processGatewayWebhookRetries |
60s |
| A DEX swap is stuck at PENDING | dexConfirmationSweep — check dex is enabled |
30s |
Before you conclude a job is broken, confirm the scheduler itself is alive. A
stopped cron app produces every one of these symptoms at once, and the job list
keeps showing plausible "last run" times for 24 hours after it dies. That is what
the scheduler console is for.
The API
{ cronName }.The WebSocket at the same base path (/api/admin/system/cron) carries the live
log, and is gated on view.cron too. Opening the console is what puts a browser
in the relay audience, which is what makes the cron process start publishing
ordinary log lines at all — the scheduler holds no sockets of its own, so it asks
the web process whether anyone is looking before it builds a payload.
access.cron is the third key: it gates the page at /admin/system/cron. A
role needs access.cron plus view.cron to read the console, and manage.cron
on top to press Run now.