Skip to content

perf(sync): add WithMinCheckpointInterval syncer option#865

Open
arreyder wants to merge 1 commit into
mainfrom
arreyder/perf-configurable-checkpoint-interval
Open

perf(sync): add WithMinCheckpointInterval syncer option#865
arreyder wants to merge 1 commit into
mainfrom
arreyder/perf-configurable-checkpoint-interval

Conversation

@arreyder
Copy link
Copy Markdown
Contributor

@arreyder arreyder commented May 24, 2026

Summary

Add WithMinCheckpointInterval(d time.Duration) as a SyncOpt so callers can tune how often the syncer persists the c1z file during non-forced checkpoints.

Problem

Profile of be-temporal-sync for a large-tenant connector (72 GB c1z, 180K users, 139K groups) shows 60% of sync CPU in CheckpointSyncsaveC1z → zstd compression → io.Copy. The current hardcoded minCheckpointInterval = 10s means the file is compressed and written to disk every 10 seconds.

For context:

  • This tenant's sync activity has had zero hard crashes in 15 days of data
  • All timeouts are clean activity-window exits (force-checkpoint before return)
  • The 10s interval wastes 60% of CPU on checkpoints that protect against a crash that doesn't happen

Fix

  • Rename minCheckpointInterval const to defaultMinCheckpointInterval
  • Add minCheckpointInterval time.Duration field on syncer struct
  • Add WithMinCheckpointInterval(d) option
  • Checkpoint(ctx, force=false) uses the configured interval (falls back to default 10s)
  • Checkpoint(ctx, force=true) always checkpoints (unchanged — clean exits still save)

Usage

syncer.New(connector, opts...,
    sync.WithMinCheckpointInterval(2 * time.Minute),
)

Setting 2 minutes reduces checkpoint overhead by ~12x (from every 10s to every 120s). The tradeoff: up to 2 minutes of lost work on a hard crash instead of 10 seconds.

Test plan

  • go vet ./pkg/sync/... — clean
  • go test ./pkg/sync/... — all pass
  • Default behavior unchanged (0 value falls back to 10s)
  • Negative/zero duration ignored (matches WithRunDuration pattern)

🤖 Generated with Claude Code

Checkpoints compress and persist the entire c1z SQLite file. For large
tenants (Eli Lilly: 72 GB c1z), this dominates CPU — profile shows 60%
of Lilly's sync time in saveC1z → zstd.Encode → io.Copy on every step.

The existing 10s throttle (minCheckpointInterval) is hardcoded. Add
WithMinCheckpointInterval(d) as a SyncOpt so callers (c1's sync
activity) can tune per-tenant or per-connector-size.

Higher values reduce checkpoint I/O at the cost of more lost work on
a hard crash (not a clean activity-window timeout, which always
checkpoints via force=true). Lilly's GLB connector has had zero hard
crashes in 15 days of data — only clean timeouts.

Example usage from c1:
  syncer.New(connector, opts...,
      sync.WithMinCheckpointInterval(2 * time.Minute),
  )

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@arreyder arreyder requested a review from a team May 24, 2026 14:16
Comment thread pkg/sync/syncer.go
Comment on lines +2682 to +2693
// WithMinCheckpointInterval sets the minimum time between non-forced
// checkpoints. Checkpoints compress and persist the c1z file; for large
// tenants this dominates CPU. Higher values reduce checkpoint overhead at
// the cost of more lost work on a hard crash. Default 10s.
func WithMinCheckpointInterval(d time.Duration) SyncOpt {
return func(s *syncer) {
if d > 0 {
s.minCheckpointInterval = d
}
}
}

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.

🟡 Suggestion: No tests were added for the new WithMinCheckpointInterval option. A small unit test verifying the option sets the field, rejects zero/negative durations, and that Checkpoint respects the configured interval would guard against regressions — especially since this is an exported SDK API that downstream callers will depend on.

@github-actions
Copy link
Copy Markdown
Contributor

ghost commented May 24, 2026

General PR Review: perf(sync): add WithMinCheckpointInterval syncer option

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Review mode: full
View review run

Review Summary

This PR adds a new WithMinCheckpointInterval syncer option that lets callers tune how often non-forced checkpoints persist the c1z file, addressing a real performance bottleneck for large tenants. The change is clean, additive, and preserves default behavior via a zero-value fallback to the existing 10s interval. One suggestion was made about adding unit tests for the new exported API.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • pkg/sync/syncer.go:2682-2693 — Missing unit tests for the new WithMinCheckpointInterval option (field setting, zero/negative rejection, checkpoint interval behavior).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/sync/syncer.go`:
- Around line 2682-2693: Add a unit test for `WithMinCheckpointInterval`. The test should verify: (1) the option correctly sets `minCheckpointInterval` on the syncer struct, (2) zero and negative durations are rejected (field stays at zero value), and (3) `Checkpoint(ctx, false)` skips the checkpoint when called within the configured interval. Follow the pattern of other `SyncOpt` tests in the package.

Copy link
Copy Markdown
Contributor

@ghost ghost left a comment

Choose a reason for hiding this comment

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

No blocking issues found.

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.

1 participant