Problem
PusherPing is a 30-second heartbeat that probes the Pusher event path — the client posts a ping over HTTP and the server answers with a PONG over the websocket. It was sent through API.writeWithNoDuplicatesConflictAction, so a throwaway probe was persisted to disk every 30 seconds, retried up to 10 times with doubling backoff, and could sit at the head of the single-flight sequential queue while a real user write waited behind it. Over a 4-hour window it was the most retried command in the app: 5,075 attempts across 2,924 users, versus 1,135 for the next-highest command.
Solution
Move PUSHER_PING out of WRITE_COMMANDS into SIDE_EFFECT_REQUEST_COMMANDS (with its PusherPingParams entry moved to SideEffectRequestCommandParameters) and send it via API.makeRequestWithSideEffects in pingPusher. That path is not persisted, not retried, and never enters the queue, which also removes the coupling where API.read had to wait for the write queue to drain behind a heartbeat. The probe itself is unchanged — checkForLatePongReplies still calls Pusher.reconnect() when a PONG goes missing — and the returned promise gets a no-op .catch since the Logging middleware already reports failures.
PR
#97702
Issue Owner
Current Issue Owner: @DylanDylann
Problem
PusherPingis a 30-second heartbeat that probes the Pusher event path — the client posts a ping over HTTP and the server answers with aPONGover the websocket. It was sent throughAPI.writeWithNoDuplicatesConflictAction, so a throwaway probe was persisted to disk every 30 seconds, retried up to 10 times with doubling backoff, and could sit at the head of the single-flight sequential queue while a real user write waited behind it. Over a 4-hour window it was the most retried command in the app: 5,075 attempts across 2,924 users, versus 1,135 for the next-highest command.Solution
Move
PUSHER_PINGout ofWRITE_COMMANDSintoSIDE_EFFECT_REQUEST_COMMANDS(with itsPusherPingParamsentry moved toSideEffectRequestCommandParameters) and send it viaAPI.makeRequestWithSideEffectsinpingPusher. That path is not persisted, not retried, and never enters the queue, which also removes the coupling whereAPI.readhad to wait for the write queue to drain behind a heartbeat. The probe itself is unchanged —checkForLatePongRepliesstill callsPusher.reconnect()when aPONGgoes missing — and the returned promise gets a no-op.catchsince the Logging middleware already reports failures.PR
#97702
Issue Owner
Current Issue Owner: @DylanDylann