Skip to content

Seed zero-value metrics for empty buckets in count-items#378

Open
delthas wants to merge 1 commit into
development/1from
improvement/S3UTILS-224/preseed-empty-bucket-metrics
Open

Seed zero-value metrics for empty buckets in count-items#378
delthas wants to merge 1 commit into
development/1from
improvement/S3UTILS-224/preseed-empty-bucket-metrics

Conversation

@delthas

@delthas delthas commented Mar 3, 2026

Copy link
Copy Markdown

count-items only produced metric documents for buckets that hold objects. An empty bucket yielded no document in __infostore, so Scuba's deep health check (getAnyMetric) found nothing and returned 500, causing CloudServer to disable the quota service cluster-wide (ARTESCA-17063).

This seeds zero-value entries for the empty bucket, its account and its location in getObjectMDStats() when a bucket scan yields no objects, so every known resource always has a document in __infostore.

The bucket key is derived from the __usersbucket creation date, exactly like populated buckets (S3UTILS-131), so the seeded document matches the key quota lookups use. If that date is missing, the bucket is skipped with a warning rather than written under a key that lookups could never match.

Note: this addresses only the empty-bucket case. The new-bucket window (before the first count-items run) and the Scuba deep-health-check / alert behavior are tracked separately.

Issue: S3UTILS-224

@bert-e

bert-e commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Hello delthas,

My role is to assist you with the merge of this
pull request. Please type @bert-e help to get information
on this process, or consult the user documentation.

Available options
name description privileged authored
/after_pull_request Wait for the given pull request id to be merged before continuing with the current one.
/bypass_author_approval Bypass the pull request author's approval
/bypass_build_status Bypass the build and test status
/bypass_commit_size Bypass the check on the size of the changeset TBA
/bypass_incompatible_branch Bypass the check on the source branch prefix
/bypass_jira_check Bypass the Jira issue check
/bypass_peer_approval Bypass the pull request peers' approval
/bypass_leader_approval Bypass the pull request leaders' approval
/approve Instruct Bert-E that the author has approved the pull request. ✍️
/create_pull_requests Allow the creation of integration pull requests.
/create_integration_branches Allow the creation of integration branches.
/no_octopus Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead
/unanimity Change review acceptance criteria from one reviewer at least to all reviewers
/wait Instruct Bert-E not to run until further notice.
Available commands
name description privileged
/help Print Bert-E's manual in the pull request.
/status Print Bert-E's current status in the pull request TBA
/clear Remove all comments from Bert-E from the history TBA
/retry Re-start a fresh build TBA
/build Re-start a fresh build TBA
/force_reset Delete integration branches & pull requests, and restart merge process from the beginning.
/reset Try to remove integration branches unless there are commits on them which do not appear on the source branch.

Status report is not available.

@codecov

codecov Bot commented Mar 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.23810% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 45.63%. Comparing base (128b8c7) to head (6442f99).

Files with missing lines Patch % Lines
utils/S3UtilsMongoClient.js 95.23% 1 Missing ⚠️
Additional details and impacted files
@@                Coverage Diff                @@
##           development/1     #378      +/-   ##
=================================================
+ Coverage          45.47%   45.63%   +0.15%     
=================================================
  Files                 88       88              
  Lines               6529     6550      +21     
  Branches            1372     1380       +8     
=================================================
+ Hits                2969     2989      +20     
- Misses              3510     3511       +1     
  Partials              50       50              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 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.

@delthas delthas requested a review from benzekrimaha March 3, 2026 17:19
@scality scality deleted a comment from bert-e Mar 3, 2026
@bert-e

bert-e commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Request integration branches

Waiting for integration branch creation to be requested by the user.

To request integration branches, please comment on this pull request with the following command:

/create_integration_branches

Alternatively, the /approve and /create_pull_requests commands will automatically
create the integration branches.

@delthas delthas changed the title S3UTILS-224: pre-seed zero-value metrics for empty buckets Pre-seed zero-value metrics for empty buckets Mar 4, 2026
@delthas delthas marked this pull request as draft March 9, 2026 08:42
@scality scality deleted a comment from bert-e Apr 7, 2026
@bert-e

bert-e commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Request integration branches

Waiting for integration branch creation to be requested by the user.

To request integration branches, please comment on this pull request with the following command:

/create_integration_branches

Alternatively, the /approve and /create_pull_requests commands will automatically
create the integration branches.

@scality scality deleted a comment from bert-e May 5, 2026
@scality scality deleted a comment from bert-e May 18, 2026
@scality scality deleted a comment from bert-e May 19, 2026
@scality scality deleted a comment from bert-e Jun 30, 2026
@delthas delthas force-pushed the improvement/S3UTILS-224/preseed-empty-bucket-metrics branch from c954e09 to ef5a150 Compare July 6, 2026 10:10
@delthas delthas changed the title Pre-seed zero-value metrics for empty buckets Seed zero-value metrics for empty buckets in count-items Jul 6, 2026
@delthas delthas changed the base branch from development/1.17 to development/1 July 6, 2026 10:11
@scality scality deleted a comment from bert-e Jul 6, 2026
@bert-e

bert-e commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Waiting for approval

The following approvals are needed before I can proceed with the merge:

  • the author

  • 2 peers

@claude

claude Bot commented Jul 6, 2026

Copy link
Copy Markdown

LGTM

Review by Claude Code

count-items only produced metric documents for buckets that hold
objects. An empty bucket yielded no document in __infostore, which
makes Scuba's deep health check fail and disables the quota service
cluster-wide (ARTESCA-17063).

Seed zero-value bucket, account and location entries in
getObjectMDStats() when a bucket scan yields no objects. The bucket
key is derived from the __usersbucket creation date, exactly like
populated buckets (S3UTILS-131), so the seeded document matches the
key quota lookups use; if that date is missing the bucket is skipped
with a warning rather than written under an unmatchable key.

Issue: S3UTILS-224
@delthas delthas force-pushed the improvement/S3UTILS-224/preseed-empty-bucket-metrics branch from ef5a150 to 6442f99 Compare July 7, 2026 08:47
@delthas delthas marked this pull request as ready for review July 8, 2026 09:28
@delthas delthas requested review from a team and DarkIsDude July 8, 2026 09:38
const retResult = this._handleResults(collRes, isVer);
retResult.stalled = stalledCount;

// Empty buckets produce no metric document, which disables quotas

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.

A 400 lines function are we are adding more logic, can we found something better ? I'm not sure the comment is really useful to understand the code ? Just explain the code. We can have context with git history if needed ?

const retResult = this._handleResults(collRes, isVer);
retResult.stalled = stalledCount;

// Empty buckets produce no metric document, which disables quotas

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.

this is re-implementing what _handleResults already does: every field is destructured with a 0n default, so an empty entry in collRes produces exactly the zero-value document (including the locations maps for bucket and account), there's no need to hand-build the shape we can just seed collRes before calling _handleResults

}
}
} else {
log.warn('unable to seed zero metrics for empty bucket: no creation date in __usersbucket', {

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.

this warn is not conditioned on the bucket being empty: any bucket missing its __usersbucket creation date will log "unable to seed zero metrics for empty bucket" on every count-items round, even when it holds millions of objects (for which seeding is irrelevant they already produce a document, just keyed _NaN).We should either gate it on the bucket actually being empty (Object.keys(collRes.bucket).length === 0), or reword; as written it will flood logs and mislead support

Comment on lines +446 to +455
const owner = bucketInfo.getOwner();
if (owner) {
if (!retResult.dataMetrics.account[owner]) {
retResult.dataMetrics.account[owner] = zeroDataMetrics(true);
}
// so the inflight block below tags it with the owner
if (!accountBucket) {
accountBucket = owner;
}
}

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.

can accountBucket ever be set here? Any processed entry creates the ${bucketName}_${date} bucket resource, so if we reach this block the cursor yielded nothing and accountBucket is necessarily undefined , the if (!accountBucket) check is dead. Same for if (!retResult.dataMetrics.account[owner]) => account entries only come from object entries, which would have created the bucket entry and skipped the block. And if (owner) ,can a BucketInfo really have no owner? If not I think that we can drop the guard; defensive checks on impossible states can hide the actual invariants

// cluster-wide (ARTESCA-17063); seed zeros so every resource has one.
// Key off the __usersbucket creation date, like populated buckets (S3UTILS-131).
if (bucketCreationDate) {
const bucketResource = `${bucketName}_${new Date(bucketCreationDate).getTime()}`;

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.

bucketKey => https://github.com/scality/s3utils/pull/378/changes#diff-3a778b361ddfba6106347ff0cb053bcbb1a84374fa0d7e6e6413e7c6fb6ca5cdR220 is already computed for inflights lookup; computing${bucketName}${date} a second time inline invites the two drifting apart, we should compute the unprefixed resource name once next to bucketKey and derive both.

@@ -1152,7 +1152,7 @@ describe('S3UtilsMongoClient, tests', () => {

const tests = [

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.

can we add a case for it (empty bucket, getUsersBucketCreationDate returning nothing → no seeded entry, warn emitted) ?

// Empty buckets produce no metric document, which disables quotas
// cluster-wide (ARTESCA-17063); seed zeros so every resource has one.
// Key off the __usersbucket creation date, like populated buckets (S3UTILS-131).
if (bucketCreationDate) {

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.

getObjectMDStats is also called with isTransient buckets (being deleted). Do we want to seed a zero document for those too, or should seeding be skipped so a bucket in deletion doesn't get a fresh __infostore doc? Probably harmless since the next run drops it, but worth stating in the PR description.

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.

4 participants