mirror of
https://github.com/hanzo-fi/payments.git
synced 2026-10-30 20:31:20 +00:00
* fix(coinbaseprime): avoid refetching payments on every account fetch TASK_FETCH_PAYMENTS was a child of TASK_FETCH_ACCOUNTS, so payments were re-fetched from scratch on every account sync cycle. Moving it to a top-level sibling task makes it run independently on its own schedule instead of being triggered by every account fetch. Backport of fix from PR #657 (fd62842). Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * fix(coinbaseprime): fix cursor reset causing full refetch on every cycle Without advanceCursor, when Coinbase returns an empty next_cursor at end-of-pagination the state was reset to an empty cursor, causing the next run to refetch all transactions from the beginning. - Extract paymentsState into shared incrementalState in state.go - Introduce advanceCursor: keep the previous cursor when next_cursor is empty so the pagination marker is never wiped Backport of fix from PR #657 (fd62842). Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * test(coinbaseprime): add unit tests for advanceCursor Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Claude Sonnet 4.6 <[email protected]>
32 lines
1.3 KiB
Go
32 lines
1.3 KiB
Go
package coinbaseprime
|
|
|
|
// incrementalState persists the opaque Coinbase Prime pagination cursor
|
|
// between fetch cycles. On each call the plugin sends Cursor as the
|
|
// `cursor` query param; Coinbase returns records strictly after it.
|
|
//
|
|
// First-run state is the zero value (empty Cursor) — the client omits the
|
|
// query param and Coinbase returns the oldest records first under the
|
|
// pinned `sort_direction=ASC`.
|
|
//
|
|
// The cursor is treated as opaque: no assumption about its format or
|
|
// lifetime is made. It is persisted verbatim and updated only when
|
|
// Coinbase returns a non-empty `next_cursor`. Coinbase returns an empty
|
|
// next_cursor at end-of-pagination; we keep the previous cursor in that
|
|
// case so the marker does not reset to the start of history. The cost is
|
|
// re-fetching the last page each cycle — the framework dedupes emitted
|
|
// records, so this is cheap and safe.
|
|
type incrementalState struct {
|
|
Cursor string `json:"cursor"`
|
|
}
|
|
|
|
// advanceCursor returns the cursor value to persist after a page
|
|
// response. If Coinbase returned a non-empty next_cursor, use it;
|
|
// otherwise keep the previous cursor so end-of-pagination does not wipe
|
|
// the marker.
|
|
func advanceCursor(oldCursor, nextCursor string) string {
|
|
if nextCursor != "" {
|
|
return nextCursor
|
|
}
|
|
return oldCursor
|
|
}
|