Skip to content

Improve chain selection for unordered batch creation - #683

Merged
DZakh merged 5 commits into
mainfrom
dz/improve-unordered-strategy
Aug 13, 2025
Merged

DZakh merged 5 commits into
mainfrom
dz/improve-unordered-strategy

Conversation

@DZakh

@DZakh DZakh commented Aug 13, 2025 •

Copy link
Copy Markdown
Member

Previously, when we created a batch, we tried to get items from a new chain every time.

The updated logic now prefers chains which are most behind. This is especially nice for indexers like UNIV4 where after indexing for a few hours, all chains besides base and optimism catch up to head, and we are left only with two chains left. We lose the HyperSync concurrency optimization. With this change, Base and optimism will have higher priority and progress with all the other changes simultaneously. Always guaranteeing that we have events and buffers to process (processing a full batch)

So there's no drop from 10k events per second to 4k events per second.

Summary by CodeRabbit

  • New Features

    • Added groundwork for unordered batch processing, selecting and prioritizing chains with eligible batch items.
  • Behavior Changes

    • Replaced “queue size” with “buffer size” across metrics, reporting and active-indexing checks.
  • Performance

    • Switched to a single-pass, per-chain batching flow for improved throughput and per-chain metric accuracy.
  • Tests

    • Updated and added tests to reflect buffer-based metrics and unordered-batch filtering/sorting behavior.

@coderabbitai

coderabbitai Bot commented Aug 13, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Rename FetchState.queueSize → bufferSize, add Array.lastUnsafe and FetchState helpers for unordered-batch selection/sorting, switch ChainManager to prepare/filter/sort fetch-states for single-pass unordered batching, and update tests/comments to reference bufferSize.

Changes

Cohort / File(s) Summary
State & utilities
codegenerator/cli/npm/envio/src/FetchState.res, codegenerator/cli/npm/envio/src/Utils.res
Rename exported queueSize → bufferSize; add hasBatchItem, compareUnorderedBatchChainPriority, filterAndSortForUnorderedBatch; add Array.lastUnsafe helper.
Event fetching templates
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res, codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
Replace queueSize checks with bufferSize; compute preparedFetchStates = FetchState.filterAndSortForUnorderedBatch(...); iterate single-pass over preparedFetchStates to build unordered batches; use fetchState.chainId for metrics and report bufferSize in batch summaries.
Tests / scenarios
scenarios/.../RollbackDynamicContract_test.res, scenarios/.../RollbackMultichain_test.res, scenarios/test_codegen/test/ChainManager_test.res, scenarios/test_codegen/test/rollback/Rollback_test.res, scenarios/test_codegen/test/lib_tests/FetchState_test.res
Update comments/tests to reference bufferSize instead of queueSize; add unit tests for FetchState.filterAndSortForUnorderedBatch (filtering by latestFullyFetchedBlock and ordering by last-item timestamp).

Sequence Diagram(s)

sequenceDiagram
  participant CM as ChainManager
  participant FS as FetchState
  participant M as Metrics
  participant B as BatchConsumer

  CM->>FS: filterAndSortForUnorderedBatch(fetchStates)
  FS-->>CM: preparedFetchStates (filtered & sorted by last-item timestamp)
  loop single-pass over preparedFetchStates until maxBatchSize
    CM->>FS: pop items from fetchState.queue
    CM->>M: record per-chain metrics using fetchState.chainId and bufferSize
  end
  CM-->>B: emit unordered batch
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Suggested reviewers

  • JonoPrest
  • JasoonS

Poem

I buffered my carrots, not queued them tonight,
LastUnsafe peeked and the ordering felt right.
One-pass I hop through the sorted array bed,
Per-chain taps of metrics, orange and red.
Hop-hop, batch ready; the warren’s fed. 🥕🐇

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dz/improve-unordered-strategy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
codegenerator/cli/npm/envio/src/Utils.res (1)

253-254: Document the non-empty precondition for Array.lastUnsafe (and consider fail-fast).

This helper is intentionally unsafe and will read undefined for empty arrays (index -1). Add a concise doc comment to make the contract explicit and avoid accidental misuse.

Apply this diff to add documentation:

   let last = (arr: array<'a>): option<'a> => arr->Belt.Array.get(arr->Array.length - 1)

+  /**
+   UNSAFE: Expects a non-empty array.
+   Prefer `last` when the array may be empty.
+  */
   let lastUnsafe = (arr: array<'a>): 'a => arr->Belt.Array.getUnsafe(arr->Array.length - 1)
codegenerator/cli/npm/envio/src/FetchState.res (1)

1237-1241: Add deterministic tie-breakers in comparator for equal timestamps.

Current comparator returns 0 when timestamps are equal, which can lead to non-deterministic ordering across runs. Consider tie-breaking on blockNumber, then logIndex, then chainId for stability.

Apply this diff to strengthen ordering:

-let compareUnorderedBatchChainPriority = (a: t, b: t) => {
-  // Use unsafe since we filtered out all queues without batch items
-  (a.queue->Utils.Array.lastUnsafe).timestamp - (b.queue->Utils.Array.lastUnsafe).timestamp
-}
+let compareUnorderedBatchChainPriority = (a: t, b: t) => {
+  // Use unsafe since we filtered out all queues without batch items
+  let ai = a.queue->Utils.Array.lastUnsafe
+  let bi = b.queue->Utils.Array.lastUnsafe
+  if ai.timestamp !== bi.timestamp {
+    ai.timestamp - bi.timestamp
+  } else if ai.blockNumber !== bi.blockNumber {
+    ai.blockNumber - bi.blockNumber
+  } else if ai.logIndex !== bi.logIndex {
+    ai.logIndex - bi.logIndex
+  } else {
+    a.chainId - b.chainId
+  }
+}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 91562d6 and dd6f69a.

📒 Files selected for processing (8)
  • codegenerator/cli/npm/envio/src/FetchState.res (4 hunks)
  • codegenerator/cli/npm/envio/src/Utils.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (2 hunks)
  • scenarios/erc20_multichain_factory/test/RollbackDynamicContract_test.res (1 hunks)
  • scenarios/erc20_multichain_factory/test/RollbackMultichain_test.res (1 hunks)
  • scenarios/test_codegen/test/ChainManager_test.res (1 hunks)
  • scenarios/test_codegen/test/rollback/Rollback_test.res (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{res,resi}

📄 CodeRabbit Inference Engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • scenarios/test_codegen/test/ChainManager_test.res
  • scenarios/test_codegen/test/rollback/Rollback_test.res
  • scenarios/erc20_multichain_factory/test/RollbackMultichain_test.res
  • codegenerator/cli/npm/envio/src/Utils.res
  • scenarios/erc20_multichain_factory/test/RollbackDynamicContract_test.res
  • codegenerator/cli/npm/envio/src/FetchState.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
codegenerator/cli/templates/{dynamic/**/*.hbs,static/**}

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Templates live under codegenerator/cli/templates: dynamic/ for Handlebars (.hbs), static/ for raw Rescript files copied verbatim.

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
{**/generated/src/**/*.res,codegenerator/cli/templates/static/codegen/src/**/*.res,codegenerator/cli/templates/dynamic/codegen/src/**/*.res}

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Runtime code lives in each project’s generated/src, but template versions (good for editing) are under codegenerator/cli/templates/static/codegen/src or codegenerator/cli/templates/dynamic/codegen/src.

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
codegenerator/cli/npm/envio/**

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Library-fied runtime shared across indexers lives in codegenerator/cli/npm/envio.

Files:

  • codegenerator/cli/npm/envio/src/Utils.res
  • codegenerator/cli/npm/envio/src/FetchState.res
⏰ 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). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (13)
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (1)

500-501: LGTM: rename to bufferSize is correct and consistent with FetchState API.

hasNoMoreEventsToProcess now correctly uses FetchState.bufferSize.

scenarios/erc20_multichain_factory/test/RollbackDynamicContract_test.res (1)

182-183: LGTM: comment-only rename to bufferSize.

Matches the updated FetchState API and keeps tests consistent with the new semantics.

scenarios/test_codegen/test/ChainManager_test.res (1)

210-211: LGTM: bufferSize aggregation reflects the new API.

Summing bufferSize across fetch states is the correct replacement for queueSize.

scenarios/test_codegen/test/rollback/Rollback_test.res (1)

193-194: LGTM: assertions updated to bufferSize.

Both assertions correctly align with FetchState.bufferSize after the API rename.

Also applies to: 259-260

scenarios/erc20_multichain_factory/test/RollbackMultichain_test.res (1)

269-276: Rename alignment to bufferSize looks correct.

The sum now reflects FetchState.bufferSize as intended by the PR-wide rename.

codegenerator/cli/npm/envio/src/FetchState.res (5)

1089-1089: Public helper rename to bufferSize is consistent.

This mirrors the internal change and aligns external call sites with the new naming.


1205-1214: End-block active-indexing check now correctly depends on buffered items.

Using fetchState->bufferSize > 0 when past endBlock is a sensible behavior change to drain remaining items before declaring inactivity.


1229-1236: hasBatchItem aligns with getEarliestEvent semantics.

Filtering only states whose earliest item is not ahead of latestFullyFetchedBlock is the right precondition for unordered batching.


1242-1246: Filtering and sorting pipeline is correct and efficient.

In-place sort on a fresh values array avoids mutating chain state, and the pre-filter prevents unsafe access.


261-267: Metrics update verified: IndexingBufferSize exists and is used consistently

  • Defined in codegenerator/cli/npm/envio/src/Prometheus.res (module IndexingBufferSize with gauge name "envio_indexing_buffer_size")
  • Invoked in FetchState.res at lines 266 and 1064
  • No remaining references to the legacy IndexingQueueSize

Please ensure dashboards and alerts have been updated to use the new envio_indexing_buffer_size metric.

codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (3)

185-189: Pre-filtering/sorting fetch states for unordered batch creation is a solid simplification.

This prepares a single pass over relevant chains and aligns with the new priority strategy favoring behind chains.


218-226: Per-chain metrics keyed by fetchState.chainId are correct.

Using chainId directly avoids reliance on chain objects in this path and matches the new FetchState API. The targetBlockNumber derivation is safe here since the last item just appended belongs to the same chain.


270-273: Batch buffer reporting updated to bufferSize.

The logged buffers now reflect the renamed API and will match Prometheus metrics for consistency.

Comment thread scenarios/test_codegen/test/ChainManager_test.res
@DZakh
DZakh requested a review from JonoPrest August 13, 2025 08:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (1)

198-199: Follow-up: previous 'sortedFetchStates' identifier is resolved

The earlier undefined reference is now correctly replaced with preparedFetchStates. No further action needed.

🧹 Nitpick comments (4)
scenarios/test_codegen/test/lib_tests/FetchState_test.res (2)

2689-2693: Prefer helper for consistent block timestamps

For consistency with the rest of the tests, consider using getBlockData(~blockNumber=latestBlock) to set latestFetchedBlock (timestamp aligned with blockNumber*15), instead of manually mirroring blockNumber into blockTimestamp.

Apply:

-        ~latestFetchedBlock={blockNumber: latestBlock, blockTimestamp: latestBlock},
+        ~latestFetchedBlock=getBlockData(~blockNumber=latestBlock),

2706-2710: Use lastUnsafe to avoid Option plumbing in test

Since the array is guaranteed non-empty in this test, you can simplify by using a dedicated unsafe accessor instead of Option.getUnsafe.

Apply:

-      prepared->Array.map(fs => (fs.queue->Utils.Array.last->Option.getUnsafe).blockNumber),
+      prepared->Array.map(fs => (fs.queue->Utils.Array.lastUnsafe).blockNumber),
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (2)

197-215: Make per-chain targetBlockNumber independent of global items array

Small robustness tweak: track the last popped blockNumber for the current chain locally instead of relying on items->Utils.Array.last. This decouples metrics from global state and avoids Option.getUnsafe usage here.

Apply:

-  while batchSize.contents < maxBatchSize && idx.contents < preparedNumber {
+  while batchSize.contents < maxBatchSize && idx.contents < preparedNumber {
     let fetchState = preparedFetchStates->Array.getUnsafe(idx.contents)
     let batchSizeBeforeTheChain = batchSize.contents
+    let lastBlockNumberForChain = ref(-1)
 
     let rec loop = () =>
       if batchSize.contents < maxBatchSize {
         let earliestEvent = fetchState->FetchState.getEarliestEvent
         switch earliestEvent {
         | NoItem(_) => ()
         | Item({item, popItemOffQueue}) => {
             popItemOffQueue()
             items->Js.Array2.push(item)->ignore
             batchSize := batchSize.contents + 1
+            lastBlockNumberForChain := item.blockNumber
             loop()
           }
         }
       }
     loop()
 
     let chainBatchSize = batchSize.contents - batchSizeBeforeTheChain
     if chainBatchSize > 0 {
       mutProcessingMetricsByChainId->Js.Dict.set(
         fetchState.chainId->Int.toString,
         {
           batchSize: chainBatchSize,
           // If there's the chainBatchSize,
           // then it's guaranteed that the last item belongs to the chain
-          targetBlockNumber: (items->Utils.Array.last->Option.getUnsafe).blockNumber,
+          targetBlockNumber: lastBlockNumberForChain.contents,
         },
       )
     }
 
     idx := idx.contents + 1
   }

194-197: Polish comment grammar for clarity

Minor wording improvement.

Apply:

-  // Accumulate items for all actively indexing chains
-  // the way to group as many items from a single chain as possible
-  // This way the loaders optimisations will hit more often
+  // Accumulate items across prepared chains, grouping as many items per chain as possible.
+  // This increases the hit rate of downstream loader optimizations.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd6f69a and 0652d53.

📒 Files selected for processing (2)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (2 hunks)
  • scenarios/test_codegen/test/lib_tests/FetchState_test.res (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{res,resi}

📄 CodeRabbit Inference Engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • scenarios/test_codegen/test/lib_tests/FetchState_test.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
codegenerator/cli/templates/{dynamic/**/*.hbs,static/**}

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Templates live under codegenerator/cli/templates: dynamic/ for Handlebars (.hbs), static/ for raw Rescript files copied verbatim.

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
{**/generated/src/**/*.res,codegenerator/cli/templates/static/codegen/src/**/*.res,codegenerator/cli/templates/dynamic/codegen/src/**/*.res}

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Runtime code lives in each project’s generated/src, but template versions (good for editing) are under codegenerator/cli/templates/static/codegen/src or codegenerator/cli/templates/dynamic/codegen/src.

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
⏰ 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). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (4)
scenarios/test_codegen/test/lib_tests/FetchState_test.res (1)

2669-2712: Good coverage for unordered-batch pre-filter/sort behavior

The test validates both exclusion (>latestFullyFetchedBlock) and ordering by earliest-eligible last-queue block. It exercises the public API path end-to-end. LGTM.

codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (3)

185-193: Correct: pre-filter and pre-sort fetch-states for unordered batches

Using FetchState.filterAndSortForUnorderedBatch over ChainMap.values is the right entry-point and prevents wasted scans. This aligns with the PR’s goal to prioritize chains that are furthest behind.


219-226: Ensure metrics keys are consistent across ordered/unordered paths

In unordered, the metrics key uses fetchState.chainId->Int.toString; in ordered, it uses item.chain->toChainId->Int.toString. They should resolve to the same string, but please confirm consumers don’t rely on one format or the other. If needed, normalize to a shared helper for chainId-string generation.

Would you like me to search and list all consumers of processingMetricsByChainId to confirm consistent key handling?


272-272: LGTM: bufferSize migration

Switching to FetchState.bufferSize in buffers reporting is correct and consistent with the rename throughout the codebase.


let hasBatchItem = ({queue, latestFullyFetchedBlock}: t) => {
switch queue->Utils.Array.last {
| Some(item) => item.blockNumber <= latestFullyFetchedBlock.blockNumber

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In what case is this false? Is it a defensive check?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

After refactoring a few months ago, we now have in a queue all items we fetched and even items for some partitions which are further ahead than the latest fully fetched block.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ah right because of the dynamic contracts?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, or wildcard also creates a new partition

Comment on lines +1237 to +1238
let compareUnorderedBatchChainPriority = (a: t, b: t) => {
// Use unsafe since we filtered out all queues without batch items

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
let compareUnorderedBatchChainPriority = (a: t, b: t) => {
// Use unsafe since we filtered out all queues without batch items
/** FetchStates must have items in their queues or there will be a runtime exn */
let compareUnorderedBatchChainPriority = (a: t, b: t) => {
// Use unsafe since we filtered out all queues without batch items

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Solved it differently

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Sweet, yeah I see now its internal to the function

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Cool looks good 👍🏼

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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)
codegenerator/cli/npm/envio/src/FetchState.res (1)

1244-1247: Add deterministic tie-breakers to comparator for stability across equal timestamps

When timestamps are equal, Array.sort may rely on engine stability. Add secondary keys to keep ordering deterministic and avoid churn between runs.

Apply this diff:

-    // Use unsafe since we filtered out all queues without batch items
-    (a.queue->Utils.Array.lastUnsafe).timestamp - (b.queue->Utils.Array.lastUnsafe).timestamp
+    // Use unsafe since we filtered out all queues without batch items
+    {
+      let aItem = a.queue->Utils.Array.lastUnsafe
+      let bItem = b.queue->Utils.Array.lastUnsafe
+      let dt = aItem.timestamp - bItem.timestamp
+      if dt !== 0 {
+        dt
+      } else {
+        let db = aItem.blockNumber - bItem.blockNumber
+        if db !== 0 {
+          db
+        } else {
+          let dl = aItem.logIndex - bItem.logIndex
+          if dl !== 0 {
+            dl
+          } else {
+            a.chainId - b.chainId
+          }
+        }
+      }
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bd9f66 and 3abe72e.

📒 Files selected for processing (1)
  • codegenerator/cli/npm/envio/src/FetchState.res (4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}

📄 CodeRabbit Inference Engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • codegenerator/cli/npm/envio/src/FetchState.res
codegenerator/cli/npm/envio/**

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Library-fied runtime shared across indexers lives in codegenerator/cli/npm/envio.

Files:

  • codegenerator/cli/npm/envio/src/FetchState.res
⏰ 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). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (5)
codegenerator/cli/npm/envio/src/FetchState.res (5)

261-267: Metric rename and buffer size computation look correct

Switching to bufferSize and wiring Prometheus.IndexingBufferSize.set(~bufferSize, ...) is consistent with the new terminology and intent.


1089-1089: New bufferSize helper is clear and reusable

Good extraction. Centralizing this logic will reduce drift and keep naming consistent across the codebase.


1210-1210: Correct gating of “actively indexing” when past endBlock

Using fetchState->bufferSize > 0 once past endBlock matches the expected lifecycle and prevents premature idling.


1231-1236: Filtering ensures lastUnsafe is safe

hasBatchItem correctly guarantees that queues are non-empty and contain an eligible batch item before sorting, making lastUnsafe safe to use later.


1238-1242: Comparator’s use of timestamp on Internal.eventItem is correct
Confirmed that in codegenerator/cli/npm/envio/src/Internal.res (lines 136–142) the eventItem type declares a timestamp: int field. There is no blockTimestamp on Internal.eventItem, so the comparator at FetchState.res:1238–1242 may safely use .timestamp. No changes required.

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.

2 participants