Skip to content

Commit

Permalink
Fix realtime error crashing service (#324)
Browse files Browse the repository at this point in the history
* add error handling for realtime http errors

* remove lint error

* chore: changeset
  • Loading branch information
0xOlias authored Aug 18, 2023
1 parent 66fda60 commit ab3d684
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/tender-pandas-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ponder/core": patch
---

Fixed a bug where the realtime sync service would crash on bad requests. Now, a warning will be logged and the service will wait until the next poll.
11 changes: 0 additions & 11 deletions examples/token-erc20/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,6 @@ ponder.on("AdventureGold:Approval", async ({ event, context }) => {
ponder.on("AdventureGold:OwnershipTransferred", async ({ event, context }) => {
const { Account } = context.entities;

const accounts = await Account.findMany({
where: {
id: {
ends_with: "123",
},
balance: {
equals: 123n,
},
},
});

await Account.upsert({
id: event.params.previousOwner,
create: {
Expand Down
47 changes: 47 additions & 0 deletions packages/core/src/realtime-sync/service.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { type EIP1193RequestFn, HttpRequestError } from "viem";
import { beforeEach, expect, test, vi } from "vitest";

import { accounts, usdcContractConfig, vitalik } from "@/_test/constants";
Expand All @@ -25,6 +26,11 @@ const network: Network = {
maxRpcRequestConcurrency: 10,
};

const rpcRequestSpy = vi.spyOn(
network.client as { request: EIP1193RequestFn },
"request"
);

const logFilters: LogFilter[] = [
{
name: "USDC",
Expand Down Expand Up @@ -198,6 +204,47 @@ test("handles new blocks", async (context) => {
await service.kill();
});

test("handles error while fetching new latest block gracefully", async (context) => {
const { common, eventStore } = context;

const service = new RealtimeSyncService({
common,
eventStore,
logFilters,
network,
});

await service.setup();
await service.start();

await sendUsdcTransferTransaction();
await testClient.mine({ blocks: 1 });

// Mock a failed new block request.
rpcRequestSpy.mockRejectedValueOnce(
new HttpRequestError({ url: "http://test.com" })
);
await service.addNewLatestBlock();

// Now, this one should succeed.
await service.addNewLatestBlock();

await service.onIdle();

const blocks = await eventStore.db.selectFrom("blocks").selectAll().execute();
expect(blocks).toHaveLength(6);
expect(blocks.map((block) => blobToBigInt(block.number))).toMatchObject([
16379996n,
16379997n,
16379998n,
16379999n,
16380000n,
16380001n,
]);

await service.kill();
});

test("emits realtimeCheckpoint events", async (context) => {
const { common, eventStore } = context;

Expand Down
15 changes: 12 additions & 3 deletions packages/core/src/realtime-sync/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,18 @@ export class RealtimeSyncService extends Emittery<RealtimeSyncEvents> {

// This method is only public for to support the tests.
addNewLatestBlock = async () => {
const block = await this.getLatestBlock();
const priority = Number.MAX_SAFE_INTEGER - hexToNumber(block.number);
this.queue.addTask(block, { priority });
try {
const block = await this.getLatestBlock();
const priority = Number.MAX_SAFE_INTEGER - hexToNumber(block.number);
this.queue.addTask(block, { priority });
} catch (error) {
// Do nothing, log the error. Might consider a retry limit here after which the service should die.
this.common.logger.error({
service: "realtime",
msg: "Error while fetching latest block",
error: error as Error,
});
}
};

private buildQueue = () => {
Expand Down

1 comment on commit ab3d684

@vercel
Copy link

@vercel vercel bot commented on ab3d684 Aug 18, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.