Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions packages/daemon/__tests__/machines/SyncMachine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -590,3 +590,83 @@ describe('Event handling', () => {
expect(currentState.matches(`${SYNC_MACHINE_STATES.CONNECTED}.${CONNECTED_STATES.handlingReorgStarted}`)).toBeTruthy();
});
});

describe('Error handling', () => {
it('should transition to ERROR state when metadataDiff invoke errors', () => {
const MockedFetchMachine = SyncMachine.withConfig({
actions: {
startStream: () => {},
storeEvent: () => {},
logEventError: () => {},
stopHealthcheckPing: () => {},
},
guards: {
invalidPeerId: () => false,
invalidStreamId: () => false,
invalidNetwork: () => false,
},
});

let currentState = untilIdle(MockedFetchMachine);

// Transition to detectingDiff state
currentState = MockedFetchMachine.transition(currentState, {
type: EventTypes.FULLNODE_EVENT,
event: VERTEX_METADATA_CHANGED as unknown as FullNodeEvent,
});

expect(currentState.matches(`${SYNC_MACHINE_STATES.CONNECTED}.${CONNECTED_STATES.handlingMetadataChanged}.detectingDiff`)).toBeTruthy();

// Simulate metadataDiff service error by sending error.platform event
// This is what xstate sends internally when an invoked service rejects
currentState = MockedFetchMachine.transition(currentState, {
type: 'error.platform.SyncMachine.CONNECTED.handlingMetadataChanged.detectingDiff:invocation[0]',
data: new Error('Database connection failed'),
} as any);

// Should have transitioned to ERROR state due to metadataDiff failure
expect(currentState.matches(SYNC_MACHINE_STATES.ERROR)).toBeTruthy();
});

it('should NOT get stuck in detectingDiff when metadataDiff errors (regression test for COE)', () => {
// This test ensures the fix for the COE is in place:
// Previously, without onError handler, the machine would get stuck in detectingDiff
// Now it should transition to ERROR state

const MockedFetchMachine = SyncMachine.withConfig({
actions: {
startStream: () => {},
storeEvent: () => {},
logEventError: () => {},
stopHealthcheckPing: () => {},
},
guards: {
invalidPeerId: () => false,
invalidStreamId: () => false,
invalidNetwork: () => false,
},
});

let currentState = untilIdle(MockedFetchMachine);

// Transition to detectingDiff state
currentState = MockedFetchMachine.transition(currentState, {
type: EventTypes.FULLNODE_EVENT,
event: VERTEX_METADATA_CHANGED as unknown as FullNodeEvent,
});

expect(currentState.matches(`${SYNC_MACHINE_STATES.CONNECTED}.${CONNECTED_STATES.handlingMetadataChanged}.detectingDiff`)).toBeTruthy();

// Send error event - this should trigger the onError handler
currentState = MockedFetchMachine.transition(currentState, {
type: 'error.platform.SyncMachine.CONNECTED.handlingMetadataChanged.detectingDiff:invocation[0]',
data: new Error('Connection pool exhausted'),
} as any);

// The machine should NOT be stuck in detectingDiff anymore
expect(currentState.matches(`${SYNC_MACHINE_STATES.CONNECTED}.${CONNECTED_STATES.handlingMetadataChanged}.detectingDiff`)).toBeFalsy();

// It should be in ERROR state
expect(currentState.matches(SYNC_MACHINE_STATES.ERROR)).toBeTruthy();
});
});
2 changes: 1 addition & 1 deletion packages/daemon/__tests__/services/services.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,7 @@ describe('metadataDiff', () => {

await expect(metadataDiff({} as any, event as any)).rejects.toThrow('Mock Error');
expect(mockDb.destroy).toHaveBeenCalled();
expect(logger.error).toHaveBeenCalledWith('e', new Error('Mock Error'));
expect(logger.error).toHaveBeenCalledWith('metadataDiff error', new Error('Mock Error'));
});

it('should handle transaction transactions that are not voided anymore', async () => {
Expand Down
1 change: 1 addition & 0 deletions packages/daemon/src/machines/SyncMachine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ export const SyncMachine = Machine<Context, any, Event>({
invoke: {
src: 'metadataDiff',
onDone: { actions: ['metadataDecided'] },
onError: `#${SYNC_MACHINE_STATES.ERROR}`,
},
on: {
METADATA_DECIDED: [
Expand Down
15 changes: 8 additions & 7 deletions packages/daemon/src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,11 @@ export const METADATA_DIFF_EVENT_TYPES = {
const DUPLICATE_TX_ALERT_GRACE_PERIOD = 10; // seconds

export const metadataDiff = async (_context: Context, event: Event) => {
const mysql = await getDbConnection();
let mysql;

try {
mysql = await getDbConnection();

const fullNodeEvent = event.event as StandardFullNodeEvent;
const {
hash,
Expand Down Expand Up @@ -166,10 +168,12 @@ export const metadataDiff = async (_context: Context, event: Event) => {
originalEvent: event,
};
} catch (e) {
logger.error('e', e);
logger.error('metadataDiff error', e);
return Promise.reject(e);
} finally {
mysql.destroy();
if (mysql) {
mysql.destroy();
}
}
};

Expand Down Expand Up @@ -466,10 +470,7 @@ export const handleVertexAccepted = async (context: Context, _event: Event) => {
await mysql.commit();
} catch (e) {
await mysql.rollback();
console.error('Error handling vertex accepted', {
error: (e as Error).message,
stack: (e as Error).stack,
});
logger.error('Error handling vertex accepted', e);

throw e;
} finally {
Expand Down