mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-08-30 23:37:08 +00:00
Compose replication scheduling as a service feature
This commit is contained in:
@@ -131,38 +131,41 @@ that request can be performed. A provider module must not subscribe to the
|
||||
application resume lifecycle merely because it can construct a transport.
|
||||
|
||||
Self-hosted LiveSync will compose one LiveSync-owned serviceFeature as the
|
||||
replication scheduling boundary. The serviceFeature constructs one private
|
||||
scheduling controller and connects it to `AppLifecycleService`, settings
|
||||
lifecycle events, and the periodic timer. The controller owns only scheduling
|
||||
state and transitions: external-poller ownership, Continuous ownership of
|
||||
recurring work, the daemon's satisfied initial OneShot marker, resume
|
||||
coalescing, and periodic-timer reconciliation. It does not register handlers
|
||||
or acquire `LiveSyncBaseCore`.
|
||||
replication scheduling boundary. The serviceFeature creates one private
|
||||
scheduling context and passes it to module-level transition functions. The
|
||||
context contains only scheduling state and narrow collaborators; the functions
|
||||
implement external-poller ownership, Continuous ownership of recurring work,
|
||||
the daemon's satisfied initial OneShot marker, resume coalescing, and
|
||||
periodic-timer reconciliation. They do not register handlers or acquire
|
||||
`LiveSyncBaseCore`.
|
||||
|
||||
The controller receives narrow collaborators for readiness and suspension
|
||||
queries, current settings, `ReplicationService`, periodic-timer control, and
|
||||
diagnostic logging. The surrounding serviceFeature owns lifecycle registration
|
||||
and adapts those Services to the controller. It returns a focused control view
|
||||
containing only the daemon operations to select external polling and mark the
|
||||
initial OneShot as satisfied. The host may retain that view for the CLI, but
|
||||
must not expose the controller's mutable state or recover it from a core-keyed
|
||||
global or `WeakMap`.
|
||||
The context receives narrow collaborators for readiness and suspension queries,
|
||||
current settings, `ReplicationService`, periodic-timer control, and diagnostic
|
||||
logging. The surrounding serviceFeature owns the context lifetime, lifecycle
|
||||
registration, and adaptation from those Services. It returns a focused control
|
||||
view containing only the daemon operations to select external polling and mark
|
||||
the initial OneShot as satisfied. Core construction passes a frozen bundle of
|
||||
built-in feature views to host composition, without retaining those views as
|
||||
public `LiveSyncBaseCore` properties. The CLI injects the scheduling view into
|
||||
its command context; other hosts may ignore it. No host may expose the context's
|
||||
mutable state or recover it from a core-keyed global or `WeakMap`.
|
||||
|
||||
This boundary is not a ServiceModule merely because it owns state. It neither
|
||||
owns a shared external resource nor supplies a general operational capability
|
||||
to several unrelated consumers. If a future consumer needs a stable shared
|
||||
scheduling capability beyond the focused CLI view, that ownership decision
|
||||
must be reviewed explicitly rather than widening the controller implicitly.
|
||||
must be reviewed explicitly rather than widening the returned view implicitly.
|
||||
|
||||
The scheduling controller uses persisted settings, `ReplicationService`, and
|
||||
the active support declaration. It does not branch on `remoteType` or use
|
||||
The scheduling functions use persisted settings, `ReplicationService`, and
|
||||
the active support declaration. They do not branch on `remoteType` or use
|
||||
`instanceof` as a capability test. Commonlib owns the trigger-aware replication
|
||||
contract; the host owns application lifecycle wiring.
|
||||
|
||||
The existing `onResumed` event remains the eligible-resume boundary after
|
||||
initial readiness, settings application, and visibility recovery. It is not
|
||||
redefined as a once-per-process event. The controller coalesces duplicate work
|
||||
within one lifecycle generation and preserves readiness and suspension gates:
|
||||
redefined as a once-per-process event. The context-backed functions coalesce
|
||||
duplicate work within one lifecycle generation and preserve readiness and
|
||||
suspension gates:
|
||||
|
||||
- configured Continuous replication starts only through an active Continuous
|
||||
role;
|
||||
@@ -177,7 +180,7 @@ within one lifecycle generation and preserves readiness and suspension gates:
|
||||
`ReplicationService` remains responsible for readiness checks, bounded finite
|
||||
activity, failure processing, and replication timing. It exposes distinct
|
||||
user-initiated and unattended entry points, or a typed request which carries
|
||||
interaction authority. The scheduling controller never calls a concrete
|
||||
interaction authority. The scheduling functions never call a concrete
|
||||
Replicator's `openReplication()` directly.
|
||||
|
||||
`P2P_AutoStart` remains a separate P2P room policy. It is not central
|
||||
@@ -199,17 +202,29 @@ The CLI daemon owns its initial finite convergence before its mirror scan.
|
||||
Restored settings mark that convergence as satisfied for the current lifecycle
|
||||
generation, so `syncOnStart` does not repeat it. In `--interval` mode, the
|
||||
daemon poller is the sole recurring remote-poll scheduler. In changes-feed mode,
|
||||
the controller starts one configured Continuous session when supported;
|
||||
otherwise it may enable the configured generic periodic timer. Continuous has
|
||||
precedence when both are configured.
|
||||
the scheduling functions start one configured Continuous session when
|
||||
supported; otherwise they may enable the configured generic periodic timer.
|
||||
Continuous has precedence when both are configured.
|
||||
|
||||
The controller starts resume work synchronously far enough to reserve
|
||||
The resume function starts work synchronously far enough to reserve
|
||||
Continuous ownership, then lets the lifecycle handler settle without awaiting
|
||||
network completion. Concurrent resume notifications share one internal
|
||||
operation. Periodic reconciliation therefore observes the reservation before
|
||||
it can enable a competing timer. A failed operation is logged and releases the
|
||||
coalescing slot so a later resume can retry.
|
||||
|
||||
Coalescing applies only within one observed lifecycle generation. If the
|
||||
application suspends and resumes while an earlier operation is still settling,
|
||||
the context retains the newer generation and runs it after the earlier
|
||||
operation releases the slot. A result from the obsolete generation cannot
|
||||
change recurring-work ownership or initiate a OneShot fallback for the newer
|
||||
generation.
|
||||
|
||||
Disabling an interval does not retract a callback which the runtime has already
|
||||
queued. Each Periodic callback therefore rechecks lifecycle eligibility,
|
||||
readiness, suspension, configuration, external-poller ownership, and
|
||||
Continuous ownership immediately before it requests replication.
|
||||
|
||||
### Use a fixed current-provider definition
|
||||
|
||||
Commonlib defines the canonical current remote kinds, provider contract,
|
||||
|
||||
@@ -63,8 +63,9 @@ actual journal result.
|
||||
Add the LiveSync-owned replication scheduling serviceFeature, remove the resume
|
||||
handler from `ModuleReplicatorCouchDB`, and route CouchDB Continuous and OneShot
|
||||
Sync plus Object Storage `syncOnStart` through `ReplicationService`. Its private
|
||||
controller owns scheduling state and transition order; the serviceFeature owns
|
||||
lifecycle and settings-handler registration. Migrate every automatic caller to
|
||||
context owns scheduling state, module-level functions implement transitions,
|
||||
and the serviceFeature owns lifecycle and settings-handler registration.
|
||||
Migrate every automatic caller to
|
||||
the unattended entry point in this stage, so periodic and event calls cannot
|
||||
fall back to an interactive P2P role. Migrate manual commands to the
|
||||
user-initiated entry point.
|
||||
@@ -81,12 +82,14 @@ snapshot. This is the minimum publication fence for this stage. Waiting for
|
||||
in-flight adapter work and making acquisitions wait for replacement settlement
|
||||
remain part of the later active-construction migration.
|
||||
|
||||
The scheduling controller coalesces its network work internally, but an
|
||||
The scheduling context coalesces its network work internally, but an
|
||||
`onResumed` handler settles once that work has been scheduled. It does not hold
|
||||
later resume consumers until a OneShot transfer or Continuous start has
|
||||
settled. Compose the controller with narrow replication, settings, lifecycle,
|
||||
timer, and logging collaborators. Return only the daemon-facing control view;
|
||||
do not retain scheduling state in a core-keyed `WeakMap`.
|
||||
settled. Pass one private context with narrow replication, settings, lifecycle,
|
||||
timer, and logging collaborators to module-level functions. Return only the
|
||||
daemon-facing control view, pass it to host composition, and inject it into the
|
||||
CLI command context. Do not retain the view as a public `LiveSyncBaseCore`
|
||||
property or retain scheduling state in a core-keyed `WeakMap`.
|
||||
|
||||
At this boundary, existing P2P AutoSync, AutoWatch, and incoming-request
|
||||
entry points receive the same non-interactive readiness and accepted-peer gate.
|
||||
@@ -107,9 +110,9 @@ AutoWatch, and accepted incoming-request paths continue with the Stage 2 gate.
|
||||
This is a temporary migration state, not the target matrix in Part 1.
|
||||
|
||||
Apply and test the CLI scheduling precedence defined in Part 1, so the daemon
|
||||
and scheduling controller cannot schedule duplicate initial or recurring work.
|
||||
and scheduling context cannot schedule duplicate initial or recurring work.
|
||||
Replace `ModuleReplicationLifecycle` and the replication-specific
|
||||
`ModulePeriodicProcess` wiring only after equivalent controller and feature-
|
||||
`ModulePeriodicProcess` wiring only after equivalent context and feature-
|
||||
binding tests pass. Reuse the existing timer implementation behind a narrow
|
||||
timer port; changing other periodic feature owners is outside this stage.
|
||||
|
||||
@@ -280,6 +283,12 @@ Cover:
|
||||
- Object Storage `syncOnStart` through resume, including a migrated profile
|
||||
which retains `liveSync: true`;
|
||||
- existing CouchDB Continuous and OneShot paths;
|
||||
- same-generation resume coalescing, a fresh attempt after a later lifecycle
|
||||
generation, and rejection of an obsolete generation's OneShot fallback;
|
||||
- a queued Periodic callback rechecking lifecycle and recurring-work ownership
|
||||
after its interval has been disabled;
|
||||
- the daemon's satisfied initial OneShot marker being consumed even when a
|
||||
Continuous start throws, so a later resume may retry normally;
|
||||
- periodic, database-save, editor-save, file-open, merge, and daemon triggers
|
||||
remaining free of dialogues;
|
||||
- manual P2P and configured peer-targeted flows remaining available;
|
||||
|
||||
Reference in New Issue
Block a user