Skip to content

fix(#610): remove orphaned EventProcessor; add DuplicateStats to idempotency#682

Open
playmaker410 wants to merge 478 commits into
Vatix-Protocol:mainfrom
playmaker410:fix/610-remove-orphaned-event-processor
Open

fix(#610): remove orphaned EventProcessor; add DuplicateStats to idempotency#682
playmaker410 wants to merge 478 commits into
Vatix-Protocol:mainfrom
playmaker410:fix/610-remove-orphaned-event-processor

Conversation

@playmaker410

@playmaker410 playmaker410 commented Jun 30, 2026

Copy link
Copy Markdown

Closes #610

Problem

src/services/event-processor.ts contained an EventProcessor class that was never imported or used anywhere in the production code path. It had three design issues:

  1. Unbounded memory growth — held an in-memory Set<string> of every seen event ID, growing forever with the process lifetime.
  2. Wrong logging — used console.warn / console.error instead of the structured ILogger used everywhere else in the codebase.
  3. Wrong type surface — its IndexerEvent interface wrapped the legacy matching-engine Trade type, not RawChainEvent used by the real indexer.

Deduplication is already fully enforced at the DB boundary via IndexerProcessedEvent + apps/indexer/src/idempotency.ts.

Changes

File Action
src/services/event-processor.ts Deleted (orphaned, zero callers)
src/services/event-processor.test.ts Deleted (companion test for deleted file)
apps/indexer/src/idempotency.ts Added DuplicateStats class
apps/indexer/src/idempotency.test.ts Added 12 unit tests for DuplicateStats
apps/indexer/src/ingestion.ts Wired DuplicateStats into PollingIngestionLoop
apps/indexer/src/ingestion.test.ts Added 3 tests covering accumulation, heartbeat log, stop() log
CHANGELOG.md Entry added under Unreleased

DuplicateStats — integrated into the ingestion loop

DuplicateStats replaces the observability surface EventProcessor offered (totalInserted, totalDuplicates, toLogFields(), reset()) but:

  • Holds no event IDs in memory — the DB is the source of truth for deduplication.
  • Is wired into PollingIngestionLoop as a process-lifetime counter:
    • Accumulates written/skipped counts from each BatchWriteResult after every batchWriter.write() call.
    • Emits totalInserted and totalDuplicates in every indexer.heartbeat log.
    • Emits totalInserted and totalDuplicates in the final stop() log.

Tests

15 new unit tests total:

  • 12 in idempotency.test.ts: zero state, record(inserted), record(duplicate), accumulated counts, recordBatch(), toLogFields() snapshot, reset(), integration with insertIfNew / insertAllIfNew.
  • 3 in ingestion.test.ts: accumulation across batches, heartbeat log includes stats, stop() log includes stats.

No regressions

  • No production import of EventProcessor existed — this is a pure dead-code removal plus stats wiring.
  • All existing idempotency.test.ts, batchWriter.test.ts, and ingestion.test.ts suites are unaffected.

Mimah97 and others added 30 commits May 27, 2026 20:07
…ons-route-242

chore(api): add env vars for positions route to .env.example
…sma-schema-243

test(api): add Vitest test for Prisma schema
…validator-type-244

feat(api): add TypeScript type for migration validator
…e/onboarding-tasks

Feature/onboarding tasks
…-env-example

chore: add Redis env vars to .env.example
…ve-error-handler-log

fix: improve error handler log message with structured fields
…pi-input-validation

feat: add input validation to OpenAPI stub
…ent-rate-limiter

docs: document rate limiter in docs/rate-limiting.md
…sor-env-example

docs: add indexer cursor env example
…atix-Protocol#349

- Vatix-Protocol#346 [api]: Add Vitest test for docker-compose.yml
  Added tests/docker-compose.test.ts that validates the compose file
  exists, defines postgres and redis services, exposes the expected
  ports, and declares named volumes for persistence.

- Vatix-Protocol#347 [indexer]: Add TypeScript type for metrics log
  Added IndexerMetricsLog interface to apps/indexer/src/metrics.ts and
  used it with a 'satisfies' check in main.ts when logging the startup
  metrics snapshot. No 'any' in new code; exported from metrics module.

- Vatix-Protocol#348 [oracle]: Improve log messages in submission queue
  Replaced all console.log/warn/error calls in oracle-service.ts with
  structured Logger calls (info/warn/error). Logger is injected via
  OracleServiceConfig.logger (optional, defaults to no-op) so existing
  tests require no changes. Each log entry carries structured fields
  (marketId, source, error, attempt, delayMs) at the appropriate level.

- Vatix-Protocol#349 [workers]: Add input validation to finalization job
  Added FinalizationValidationError (statusCode=400) and a guard at the
  top of FinalizationJob.run() that throws it when challengeWindowSeconds
  is negative, NaN, or Infinity. Added job.test.ts covering the invalid
  and valid input cases.
…-api-indexer-oracle-workers-improvements

feat(api,indexer,oracle,workers): address issues Vatix-Protocol#346-Vatix-Protocol#349
…env-error-handler-comment

[topup] [api] Add env var to .env.example for error handler (2)
…atix-Protocol#299 Vatix-Protocol#344

- Vatix-Protocol#297: Add input validation to test utilities
  - Add validateDatabaseUrl() function with comprehensive input validation
  - Return false for invalid inputs (non-strings, empty, invalid URLs, wrong schemes)
  - Validate parameters in cleanDatabase()
  - Add 13 test cases covering all validation scenarios

- Vatix-Protocol#298: Document logger in docs/
  - Create logger.md with complete Logger API documentation
  - Include usage examples for routes, workers, and databases
  - Document log levels, environment configuration, and best practices
  - Add link from README

- Vatix-Protocol#299: Add env var for config types to .env.example
  - Add Configuration Types Reference section
  - Document REQUIRED vs OPTIONAL distinction
  - Explain Enum, Integer, URL, and String type validation
  - Add missing env vars: ORACLE_CHALLENGE_WINDOW_SECONDS, ORACLE_LOG_LEVEL, LOG_LEVEL

- Vatix-Protocol#344: Document graceful shutdown in docs/
  - Create graceful-shutdown.md with comprehensive guide
  - Include signal handling, worker pattern, and resource cleanup
  - Add timeout protection and testing strategies
  - Cover environment-specific considerations (Docker, Kubernetes)
  - Add link from README
…xample

chore: add comprehensive env var documentation to .env.example (Vatix-Protocol#230)
Mimah97 and others added 28 commits June 27, 2026 16:01
…-queue-migration

feat(workers): migrate oracle and settlement consumers to BullMQ (Vatix-Protocol#551)
…idate-position-routes

feat: add GET /v1/wallets/:wallet/positions/:marketId sub-route (Vatix-Protocol#556)
…openapi-docs

feat: mount interactive OpenAPI docs at /docs (Vatix-Protocol#557)
The /v1/ready endpoint was missing response body schemas for both
200 and 503 responses. Added DependencyResult component schema and
wired it into the readiness endpoint responses.
redisConnectionFromEnv() returned { url } which BullMQ does not
accept as a connection option. Parse the URL into { host, port,
password } so BullMQ workers can connect properly.
…ring

Trade.outcome was declared as String @db.VarChar(8) which bypasses
Prisma's enum validation, unlike Order.outcome which correctly uses
the Outcome enum. Align both models to use the same type.
Audit stream keys were hardcoded without REDIS_KEY_PREFIX, unlike
the settlement queue. This caused cross-environment contamination
in shared Redis deployments. Read prefix from env at construction.
…arison

The resolution parser in the workers scope was using `outcome === true`
which is redundant for boolean values and fragile if outcome type changes.
…orker"

The oracle queue nack() was using a hardcoded "nack-worker" consumer name
in xclaim, causing retried messages to be assigned to a phantom consumer
that never processes them. Messages would get stuck instead of being retried.
…Failure

Both methods had empty data: {} in their Prisma calls, making them no-ops.
updateAttempt now degrades confidence on retry. updateOnFailure now clears
candidateResolution and marks the ResolutionCandidate as REJECTED.
…-resolution-oracle-submission

Fix/minimal tasks resolution oracle submission
…eStats to idempotency

The in-memory EventProcessor in src/services/event-processor.ts was
never imported or wired into any production code path.  Deduplication
is already enforced at the DB boundary via IndexerProcessedEvent and the
idempotency helpers in apps/indexer/src/idempotency.ts.

Changes:
- Delete src/services/event-processor.ts and its companion test.
  The class held an unbounded in-memory Set<string> of seen event IDs
  (memory leak), used console.warn/error instead of structured logging,
  and wrapped the legacy matching-engine Trade type rather than the
  chain-indexer RawChainEvent type.
- Add DuplicateStats class to idempotency.ts.  Provides the same
  observability surface (totalInserted, totalDuplicates, toLogFields,
  reset) that EventProcessor offered, but without holding any IDs in
  memory — the DB is the source of truth.
- Add 12 new unit tests for DuplicateStats covering: zero state,
  record(inserted), record(duplicate), accumulated counts, recordBatch,
  toLogFields snapshot, reset, and integration with insertIfNew /
  insertAllIfNew.

Closes Vatix-Protocol#610
@Mimah97

Mimah97 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@playmaker410 fix pr and link issues

- Add private duplicateStats field to PollingIngestionLoop
- Accumulate written/skipped counts from each BatchWriteResult via
  recordBatch() after every batchWriter.write() call
- Emit toLogFields() spread in heartbeat log (indexer.heartbeat)
- Emit toLogFields() spread in stop() log
- Add 3 new ingestion tests: accumulation across batches, heartbeat
  log includes totalInserted/totalDuplicates, stop() log includes
  totalInserted/totalDuplicates

Closes Vatix-Protocol#610
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.