Health branch - #143
Open
OmniZlatoon wants to merge 3 commits into
Open
Conversation
Author
|
Good morning sir @prodbycorne , please kindly review the PR |
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
closes #123
### Walkthrough: Webhook Dispatch Issues & GET /health Status Aggregation
This walkthrough provides a comprehensive summary of the tasks completed to address the webhook dispatch documentation discrepancies and the health check status calculation gap.
Task 1: Resolving Webhook Dispatch Issues
Background Context
The codebase defined several pool.* events (such as pool.created, pool.assets_locked, etc.) as subscribable webhooks. However, the system's indexer only decodes airdrop lifecycle events, and there is no backend code path that dispatches any pool-related events. Furthermore, the test delivery endpoint (POST /webhooks/:id/test) sent a synthetic pool.assets_locked payload, which misled clients into believing pool events were fully functional.
Implementation Details
To resolve this without breaking existing database entries, third-party subscriptions, or tests, we chose to retain the POOL_EVENTS registry as a forward-looking placeholder while updating all relevant documentation and codebase comments to be explicit.
1. Codebase Registry Update
File modified:
webhookEvents.js
Change: Added an explicit caveat comment above POOL_EVENTS explaining that these events are not currently dispatched. This follows the exact pattern already established for AIRDROP_EVENTS.
Code Change:
javascript
// None of the pool events are actually dispatched by the codebase today (the
// event indexer only parses airdrop lifecycle events). They are registered
// here as forward-looking placeholders, but subscribing to them will not
// trigger any deliveries until the corresponding indexer and dispatch logic
// are implemented.
const POOL_EVENTS = Object.freeze([
'pool.created',
'pool.assets_locked',
'pool.assets_unlocked',
'pool.rewards_distributed',
'pool.closed',
]);
2. User Documentation Update
File modified:
README.md
Changes:
Updated the Webhook Delivery System setup section to group events by active (airdrop.failed) and planned (airdrop.created, airdrop.executing, airdrop.completed, recipient.claimed) status.
Updated the "Supported event types" table to explicitly label all pool.* events as Planned (not yet implemented).
Updated the worked registration POST /api/v1/webhooks example payload to use active events (airdrop.failed, price.alert) instead of unimplemented pool events.
Added a warning under #### Test endpoint to clarify that a successful test delivery (sending a synthetic pool.assets_locked payload) only validates the receiver's URL and does not imply that pool events are live in production.
3. OpenAPI Specification Update⚠️ Warning) in the endpoint description clarifying the synthetic nature of the test delivery.
File modified:
openapi.yaml
Changes:
Corrected the /api/v1/webhooks/{id}/test description and examples to indicate that it queues a synthetic pool.assets_locked payload instead of a ping event.
Added a warning box (
Expanded the WebhookEvent schema enum to contain the missing pool.* and price.alert events.
Classified the enum values in the WebhookEvent description into Active / implemented vs Planned / not yet implemented.
Updated all /api/v1/webhooks endpoint request and response examples to use active/implemented events (airdrop.failed / price.alert).
Task 2: GET /health Status Aggregation Integration
Background Context
The GET /health endpoint serves as the primary integration for external monitors, load balancers, or container probes. However, its top-level status field was only computed from Redis connectivity and two out of three background jobs (price_refresh and webhook_retry_worker). The health of the third background job (airdrop_expiry) was reported in the body but ignored in the aggregate status calculation. If airdrop_expiry stalled, the status remained 'ok'.
Implementation Details
We refactored the status computation to include all three jobs. Additionally, we extracted the logic into a named helper to make it loop-based, avoiding hardcoded boolean variables that are prone to future regression.
1. Core Refactoring
File modified:
index.js
Change: Implemented the computeAggregateStatus(redisConnected, jobHealths) helper function and updated the /health handler to invoke it.
Code Change:
javascript
/**
*/
function computeAggregateStatus(redisConnected, jobHealths) {
if (!redisConnected) {
return 'unhealthy';
}
const anyStalled = jobHealths.some((job) => job.stalled);
if (anyStalled) {
return 'unhealthy';
}
const anyUnhealthy = jobHealths.some((job) => !job.healthy);
if (anyUnhealthy) {
return 'degraded';
}
return 'ok';
}
// Inside app.get('/health', ...)
const status = computeAggregateStatus(redisConnected, [
priceRefreshHealth,
webhookWorkerHealth,
airdropExpiryHealth,
]);
2. Test Verification & Regression Coverage
File modified:
health.test.js
Changes:
Mocked ../src/jobs/airdropExpiry at the top level to return healthy stats by default. This avoids breaking existing status tests since the unstarted airdropExpiry job defaults to an unhealthy/pre-run state.
Updated the test that checks if the jobs response field contains price_refresh and webhook_retry_worker to also assert the presence and shape of airdrop_expiry.
Added a regression test asserting that if only the airdrop_expiry job is stalled (with others healthy), the top-level status degrades to 'unhealthy'.
Added a regression test asserting that if the airdrop_expiry job has not yet run (healthy: false, stalled: false), the status is 'degraded'.
Verification Summary
All automated tests in the repository were run to verify the correctness of the changes and guard against regressions:
bash
npm test
Test Suite Output
PASS test/webhookDispatcher.test.js
PASS test/airdrops-service.test.js
PASS test/auth.test.js
PASS test/eventPoller.test.js
PASS test/errorHandler.test.js
PASS test/prices.test.js
PASS test/webhooks.routes.test.js
PASS test/validate.test.js
PASS test/indexerParser.test.js
PASS test/paginationContract.test.js
PASS test/api-docs.test.js
PASS test/webhookSignature.test.js
PASS test/apiRateLimit.test.js
PASS test/config.test.js
PASS test/cors.test.js
PASS test/coingecko.test.js
PASS test/circuitBreaker.test.js
PASS test/deliveryRepository.test.js
PASS test/indexerRoutes.test.js
PASS test/alerts-routes.test.js
PASS test/stellarDex.test.js
PASS test/coinmarketcap.test.js
PASS test/airdrops.test.js
PASS test/priceWebSocket.test.js
PASS test/webhookRepository.test.js
PASS test/resilience.test.js
PASS test/priceOracle.test.js
PASS test/airdropExpiry.test.js
PASS test/rateLimit.test.js
PASS test/leaderElection.test.js
PASS test/priceOracleCircuit.test.js
PASS test/cacheWarm.test.js
PASS test/webhooks.test.js
PASS test/alerts.test.js
PASS test/webhookEvents.test.js
PASS test/indexerStore.test.js
PASS test/pagination.test.js
PASS test/requestId.test.js
PASS test/health.test.js
Test Suites: 39 passed, 39 total
Tests: 372 passed, 372 total
Snapshots: 0 total
Time: 7.005 s
Ran all test suites.
All 372 tests passed successfully.