Skip to content

Skip non-localized entries in replication and lifecycle - #2832

Draft
francoisferrand wants to merge 5 commits into
improvement/BB-814from
improvement/BB-816-skip-non-localized-en
Draft

Skip non-localized entries in replication and lifecycle#2832
francoisferrand wants to merge 5 commits into
improvement/BB-814from
improvement/BB-816-skip-non-localized-en

Conversation

@francoisferrand

Copy link
Copy Markdown
Contributor

Stacked on #2826 (BB-814), so the base here is improvement/BB-814. This replaces #2827, which GitHub auto-closed when the branch was renamed to drop the francoisferrand- prefix.

In a clean room, an object's metadata is local but its data still lives on the source cluster: dataStoreName points at an isCRR location. Such a version has nothing local to offer, so the existing workflows must leave it alone until localization has rewritten the metadata.

BB-814 already diverted those entries in the replication populator to localization, but only when localization was configured. Otherwise they fell through and got replicated, which would copy a location the target cannot read. They are now skipped in both cases. Nothing is lost: the localization merge produces a new oplog entry with the real location, and replication picks it up then.

Lifecycle transitions get the same treatment. Localization is the only valid transition out of an isCRR location and it is driven by its own path, not by lifecycle rules, so a transition rule matching such a version is skipped and the version re-evaluated on a later scan.

LifecycleTaskV2 only calls _applyTransitionRule, it does not override it, so the single check covers both tasks.

Tested with the replication and lifecycle unit suites; the populator specs cover the disabled-localization and PENDING cases, and the new _applyTransitionRule specs assert no data-mover action and no transitionInProgress for an isCRR object, with a regular location as positive control.

Issue: BB-816

In a clean room, objects are created locally but their metadata still
points at the source cluster's location: the data itself has not been
copied over yet. Something has to notice those objects and ask for the
data to be pulled in.

The queue populator is the natural place for it, since bootstrap,
re-bootstrap and streamed updates all go through the same oplog. When an
object lands on a location flagged isCRR, publish a copyLocation action
on the data mover topic and let the existing data mover + transition
merge pipeline do the actual copy.

This is unrelated to replicationInfo, which describes replication of a
*local* object to remote sites, so the check sits before any replication
condition. Activation is simply the presence of
extensions.replication.localization.toLocation in the config; without it
nothing changes.

The populator only knows the object owner's canonical id, and resolving
an account id per entry would throttle the whole populator, so the
lookup is deferred to the transition processor, which now resolves it
once up front and stamps it back on the action - the same way the
garbage collector already does.

Issue: BB-814
AccountIdCache.isKnown() is also true for cached misses, where get()
returns undefined. The localization flow would then carry on with
target.accountId unset and surface a confusing "failed to get backbeat
client" InternalError instead of the NoSuchEntity that actually caused
it, making a bad canonical id hard to diagnose in production.

Treat a cached miss as the error it is, and only stamp the resolved
account id onto the entry when there is one.

Issue: BB-814
Initialising the vault client wrapper for every processor using assume
role auth broke the expiration processor, which has no vaultAdmin in its
config: start() threw on the missing host, and isReady() would have
waited forever on credentials nobody was fetching.

Only the transition processor receives actions without an account id, so
gate both on a vault endpoint actually being configured, and fail the
lookup explicitly if one is ever requested without it.

Also add the new clean room location to the circuit breaker probe
expectations, which enumerate every configured location.

Issue: BB-814
In a clean room, an object's metadata is local but its data still lives
on the source cluster: dataStoreName points at an isCRR location. Such a
version has nothing local to offer, so the existing workflows must leave
it alone until localization has rewritten the metadata.

The replication populator already diverted those entries to localization,
but only when localization was configured; otherwise they fell through
and got replicated, which would copy a location the target cannot read.
Skip them in both cases. Nothing is lost: the localization merge produces
a new oplog entry with the real location, and replication picks it up
then.

Lifecycle transitions get the same treatment. Localization is the only
valid transition out of an isCRR location and it has its own trigger, so
a transition rule matching such a version is simply skipped and the
version re-evaluated on a later scan.

Issue: BB-816
The rewording added in the previous commit did not carry any new
information, and only made the stacked diff harder to read: the
localization trigger comment from BB-814 already explains why the check
sits before any replication condition.

Issue: BB-816
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.64%. Comparing base (943cbb0) to head (f7e1911).

Additional details and impacted files

Impacted file tree graph

Files with missing lines Coverage Δ
extensions/lifecycle/tasks/LifecycleTask.js 91.76% <100.00%> (+0.04%) ⬆️
...xtensions/replication/ReplicationQueuePopulator.js 93.81% <100.00%> (+0.06%) ⬆️

... and 1 file with indirect coverage changes

Components Coverage Δ
Bucket Notification 80.27% <ø> (ø)
Core Library 81.30% <ø> (-0.02%) ⬇️
Ingestion 70.09% <ø> (ø)
Lifecycle 80.79% <100.00%> (+0.01%) ⬆️
Oplog Populator 85.83% <ø> (ø)
Replication 62.45% <100.00%> (+0.01%) ⬆️
Bucket Scanner 85.76% <ø> (ø)
@@                  Coverage Diff                   @@
##           improvement/BB-814    #2832      +/-   ##
======================================================
- Coverage               75.64%   75.64%   -0.01%     
======================================================
  Files                     200      200              
  Lines                   14004    14008       +4     
======================================================
+ Hits                    10594    10597       +3     
- Misses                   3400     3401       +1     
  Partials                   10       10              
Flag Coverage Δ
api:retry 9.05% <0.00%> (-0.01%) ⬇️
api:routes 8.82% <0.00%> (-0.01%) ⬇️
bucket-scanner 85.76% <ø> (ø)
ft_test:queuepopulator 9.32% <0.00%> (-0.01%) ⬇️
ingestion 12.65% <0.00%> (-0.01%) ⬇️
lib 8.77% <0.00%> (-0.06%) ⬇️
lifecycle 19.26% <50.00%> (+<0.01%) ⬆️
notification 1.01% <0.00%> (-0.01%) ⬇️
oplogPopulator 0.13% <0.00%> (-0.01%) ⬇️
replication 18.73% <0.00%> (-0.01%) ⬇️
unit 55.50% <100.00%> (+0.34%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@francoisferrand francoisferrand self-assigned this Aug 24, 2026
@francoisferrand
francoisferrand marked this pull request as ready for review August 24, 2026 12:40
@francoisferrand
francoisferrand marked this pull request as draft August 26, 2026 07:52
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