Skip to content

feat: deduplicate online license re-validation across plugin instances#11

Merged
TobbenTM merged 1 commit into
mainfrom
dedupe-license-revalidation
May 18, 2026
Merged

feat: deduplicate online license re-validation across plugin instances#11
TobbenTM merged 1 commit into
mainfrom
dedupe-license-revalidation

Conversation

@TobbenTM
Copy link
Copy Markdown
Member

Summary

  • Collapse a DAW project-load thundering herd (N plugin instances calling validate_token_online simultaneously) to a single network call per min_interval window per host — including across sandboxed sibling processes (Bitwig, Ableton 12.1 Sandbox, AU v3).
  • Three coordinated layers: an in-process std::mutex in moonbase::licensing, a cross-process file lock via a new license_store::lock_for_update() returning an RAII guard (sidecar <license>.lock so it survives delete_local_license unlinking the data file; memory_license_store backs it with an internal recursive_mutex), and reload-then-persist-under-lock inside validate_token_online.
  • New optional should_persist predicate on validate_token_online, called inside both locks immediately before the store write — the JUCE bridge's async path uses it to veto persists after clearLicense / revokeActivation / pollPendingActivation so a stale refresh can't resurrect a cleared license on disk; those bridge mutations also hold the same file lock now. The bridge additionally shares moonbase::licensing instances process-wide keyed on the full backend configuration.

Test plan

  • ctest --output-on-failure — 48 tests pass, including 7 new unit tests and a POSIX fork()-based cross-process integration test that spawns 8 children against a shared file store and asserts a single network call.
  • JUCE example app (MOONBASE_BUILD_JUCE_EXAMPLE=ON) builds and runs.
  • CI (Ubuntu / macOS / Windows) on the PR.

When a DAW project loads N plugin instances simultaneously, they each
call validate_token_online. Previously the SDK's 5-min throttle only
protected against repeats after one had written its result, and the
function didn't persist the refreshed license at all — so siblings
(including out-of-process siblings under Bitwig / Ableton 12.1 Sandbox
/ AU v3) couldn't observe each other and would all fire parallel network
requests.

Three coordinated layers now collapse this to a single network call per
min_interval window per host:

- An in-process std::mutex in moonbase::licensing for cheap fast-path
  serialization of same-process callers.
- A cross-process file lock via license_store::lock_for_update() — a new
  optional virtual returning an RAII guard. file_license_store backs it
  with a flock/LockFileEx wrapper (detail/file_lock.hpp); the lock target
  is a dedicated <license>.lock sidecar so it survives delete_local_license
  unlinking the data file. memory_license_store backs it with an internal
  recursive_mutex so the default store is safe under concurrent
  clear/validate.
- Reload-the-store-under-lock + persist-the-refresh-under-lock inside
  validate_token_online itself, so the second waiter sees the fresh
  validated_at the first writer just wrote and short-circuits via the
  throttle.

validate_token_online gains an optional should_persist predicate, called
inside both locks immediately before the store write. The JUCE bridge's
async path uses it to veto the persist when the user's generation has
moved on (clearLicense / revokeActivation / pollPendingActivation success),
which otherwise could resurrect a cleared license on disk. Those bridge
mutations now also hold the same file lock so persist and delete are
ordered relative to each other.

The bridge additionally caches moonbase::licensing instances process-wide
so plugins sharing a (endpoint, product_id, public_key, account_id, store,
fingerprint) configuration share a single SDK instance — and therefore a
single in-process mutex — across all their MoonbaseUnlockStatus instances.

Tests: 7 new unit tests plus a POSIX fork()-based cross-process
integration test that spawns 8 children against a shared file store and
asserts a single network call.
@TobbenTM TobbenTM merged commit f095246 into main May 18, 2026
4 checks passed
github-actions Bot pushed a commit that referenced this pull request May 18, 2026
# [2.2.0](v2.1.0...v2.2.0) (2026-05-18)

### Features

* deduplicate online license re-validation across plugin instances ([#11](#11)) ([f095246](f095246))
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 2.2.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant