Skip to content

Refactor document updates to Redis CAS + async Mongo write-back with retry - #220

Draft
GStones with Copilot wants to merge 3 commits into
mainfrom
copilot/refactor-document-update
Draft

Refactor document updates to Redis CAS + async Mongo write-back with retry#220
GStones with Copilot wants to merge 3 commits into
mainfrom
copilot/refactor-document-update

Conversation

Copilot AI commented May 28, 2026

Copy link
Copy Markdown
Contributor

This PR introduces a high-concurrency document update path that prioritizes cache-side atomicity and eventual consistency. Updates now use Redis CAS semantics with retry/backoff and persist to Mongo asynchronously to reduce synchronous contention while preventing stale overwrites.

  • Atomic cache update (Redis + Lua)

    • Added an atomic versioned CAS contract (IAtomicVersionCache) for cache implementations.
    • Implemented Redis Lua-based compare-and-swap in RedisCache.CompareAndSwapCache(...):
      • validates expected version
      • writes payload + next version atomically
    • Added compatibility fallback for existing cache entries missing explicit :version key.
  • Optimistic concurrency control (version/CAS)

    • DocumentBase.Update(...) now uses cache CAS when supported.
    • Version conflict remains retryable via existing bounded retry + exponential backoff flow.
    • Update payload now uses a stable cloned snapshot to avoid races between in-memory mutation and persistence.
  • Async Mongo write-back (eventual consistency)

    • After successful cache CAS, persistence is moved to background write-back (asyncWriteBack).
    • Background persistence uses versioned CAS against the document store and retries with exponential backoff.
    • On persistent write-back failure, cache entry is invalidated to avoid long-lived divergence.
  • Focused behavior coverage

    • Added a dedicated unit test for:
      • CAS conflict retry path
      • async write-back retry/success path
if atomicCache, ok := d.cache.(diface.IAtomicVersionCache); ok {
    nextVersion := d.version + 1
    snapshot, _ := cloneAny(d.data)

    _, err := atomicCache.CompareAndSwapCache(
        d.ctx, d.Key, d.version,
        &VersionCache{Version: nextVersion, Data: snapshot},
        DefaultCacheTTL,
    )
    if err == nil {
        prevVersion := d.version
        d.version = nextVersion
        go d.asyncWriteBack(snapshot, prevVersion)
    }
}

Copilot AI linked an issue May 28, 2026 that may be closed by this pull request
4 tasks
Copilot AI changed the title [WIP] Refactor document update for caching system Refactor document updates to Redis CAS + async Mongo write-back with retry May 28, 2026
Copilot AI requested a review from GStones May 28, 2026 13:47
@GStones
GStones requested a lite review from Copilot August 20, 2026 13:43

Copilot AI left a comment

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.

Pull request overview

This PR refactors DocumentBase.Update to prefer an atomic cache-side compare-and-swap (CAS) path when supported (intended for Redis), and moves the database persistence step into an asynchronous write-back with bounded retries to reduce synchronous contention.

Changes:

  • Added a new cache contract (diface.IAtomicVersionCache) for version-checked atomic updates.
  • Updated DocumentBase.Update to use cache CAS + background persistence, including snapshot cloning for async write-back.
  • Implemented Redis Lua-based CAS and added a focused unit test covering CAS retry + async write-back retry/success.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
orm/nosql/document.go Cache-first CAS update flow plus async Mongo write-back and JSON-based snapshot cloning.
orm/nosql/document_update_test.go New unit test for CAS conflict retry and async write-back retry/success.
orm/nosql/diface/icache.go Introduces IAtomicVersionCache interface for atomic versioned cache updates.
orm/nosql/cache/redis_cache.go Adds Redis Lua CAS implementation plus version-key management helpers.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread orm/nosql/document.go
Comment on lines +192 to +204
if _, err := atomicCache.CompareAndSwapCache(
d.ctx,
d.Key,
d.version,
cacheSnapshot,
DefaultCacheTTL,
); err != nil {
return err
}
prevVersion := d.version
d.version = nextVersion
go d.asyncWriteBack(snapshot, prevVersion)
return nil
Comment on lines +21 to +23
// IAtomicVersionCache provides atomic version-checked cache updates.
type IAtomicVersionCache interface {
CompareAndSwapCache(
Comment on lines +105 to +117
res := c.Eval(
ctx,
compareAndSwapLua,
[]string{key.String(), versionKey(key)},
expectedVersion,
nextVersion,
data,
expire.Milliseconds(),
)
if err := res.Err(); err != nil {
return noptions.NoVersion, err
}
return nextVersion, nil
Comment thread orm/nosql/document.go
Comment on lines +201 to +203
prevVersion := d.version
d.version = nextVersion
go d.asyncWriteBack(snapshot, prevVersion)
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.

[refactor]: refactor document update

3 participants