Skip to content

feat(compression-coordinator): Introduce max_concurrent_tasks config to limit job-handler concurrency. - #2435

Open
Bill-hbrhbr wants to merge 11 commits into
y-scope:mainfrom
Bill-hbrhbr:coordinator/limit-job-submission-concurrency
Open

feat(compression-coordinator): Introduce max_concurrent_tasks config to limit job-handler concurrency.#2435
Bill-hbrhbr wants to merge 11 commits into
y-scope:mainfrom
Bill-hbrhbr:coordinator/limit-job-submission-concurrency

Conversation

@Bill-hbrhbr

@Bill-hbrhbr Bill-hbrhbr commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Description

Limit the number of compression jobs processed concurrently to prevent the coordinator from creating an unbounded number of job-handler tasks and consuming excessive memory when a large backlog of jobs accumulates.

On restart, the coordinator first resumes tracking all jobs that were previously submitted to Spider before accepting new work. This recovery step bypasses the concurrency limit, but counts resumed jobs against it, preventing new jobs from being submitted until capacity becomes available.

This preserves the existing recovery behavior while ensuring that newly admitted jobs respect the configured processing capacity.

The concurrency limit is configured through a new max_concurrent_tasks field in ClpConfig and is populated from the configuration file.

Checklist

  • The PR satisfies the contribution guidelines.
  • This is a breaking change and that has been indicated in the PR title, OR this isn't a
    breaking change.
  • Necessary docs have been updated, OR no docs need to be updated.

Validation performed

Summary by CodeRabbit

  • New Features
    • Added configurable limits for concurrent compression tasks, with validation to prevent invalid values.
    • Improved compression job scheduling with capacity-aware queuing and FIFO processing.
    • Enhanced startup recovery for previously interrupted jobs.
    • Added clear configuration errors when invalid settings are provided.
  • Documentation
    • Added a commented configuration template covering compression coordinator settings and Spider cluster connectivity.
    • Documented polling, recovery, retry, timeout, connection-pool, and concurrency settings.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The change adds a validated concurrency limit to compression coordinator configuration. The coordinator uses a semaphore and FIFO queue for new-job scheduling, while startup recovery can launch all recovered jobs. The package template documents coordinator and Spider connection settings.

Changes

Compression coordinator concurrency

Layer / File(s) Summary
Concurrency configuration
components/clp-py-utils/clp_py_utils/clp_config.py, components/clp-rust-utils/src/clp_config/package/config.rs
Adds max_concurrent_tasks with a default of 1,000. Python validates a positive integer. Rust uses NonZeroUsize.
Concurrency-limited job scheduling
components/compression-coordinator/src/coordination.rs, components/compression-coordinator/src/error.rs
Validates the configured limit against Tokio’s semaphore maximum. New jobs enter a FIFO queue and dispatch only after permit acquisition. Each handler retains its permit until completion. Startup recovery can run without permits when capacity is unavailable.
Configuration template wiring
components/package-template/src/etc/clp-config.template.json.yaml
Documents compression coordinator settings and the required Spider cluster connection.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CompressionCoordinator
  participant JobDatabase
  participant JobHandler
  CompressionCoordinator->>JobDatabase: Fetch pending jobs when capacity exists
  CompressionCoordinator->>CompressionCoordinator: Add fetched jobs to the FIFO queue
  CompressionCoordinator->>JobHandler: Spawn handlers after acquiring permits
  JobHandler->>CompressionCoordinator: Retain the permit until completion
Loading

Possibly related PRs

  • y-scope/clp#2401: Shares the compression-coordinator crate and its Error type.
  • y-scope/clp#2404: Introduces related CompressionCoordinator configuration and crate scaffolding.
  • y-scope/clp#2417: Modifies the coordinator configuration and coordination.rs flow extended by this change.

Suggested reviewers: linzhihao-723, sitaowang1998

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding configurable concurrency limits for compression-coordinator job handlers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Bill-hbrhbr Bill-hbrhbr changed the title feat(compression-coordinator): Limit concurrent job-handler tasks. feat(compression-coordinator): Introduce max_concurrent_tasks config to limit job-handler task concurrency. Aug 1, 2026
@Bill-hbrhbr Bill-hbrhbr changed the title feat(compression-coordinator): Introduce max_concurrent_tasks config to limit job-handler task concurrency. feat(compression-coordinator): Introduce max_concurrent_tasks config to limit job-handler concurrency. Aug 1, 2026
@Bill-hbrhbr
Bill-hbrhbr marked this pull request as ready for review August 1, 2026 06:51
@Bill-hbrhbr
Bill-hbrhbr requested a review from a team as a code owner August 1, 2026 06:51

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/clp-py-utils/clp_py_utils/clp_config.py`:
- Line 798: Add a shared Tokio semaphore upper-bound validation for
max_concurrent_tasks in components/clp-py-utils/clp_py_utils/clp_config.py:798
and components/clp-rust-utils/src/clp_config/package/config.rs:488, preserving
the existing positive-value validation. In
components/compression-coordinator/src/coordination.rs:137-138, validate the
configured value before constructing job_handler_sem and return the established
configuration error when it exceeds the supported limit.

In `@components/compression-coordinator/src/coordination.rs`:
- Around line 49-52: Update the recovery admission logic around the
coordinator’s recovered-handler tracking so every recovered handler contributes
to the active count, including handlers that do not hold a permit. Prevent new
jobs from being admitted until the total active recovered and newly started
handlers is below max_concurrent_tasks, and revise the recovery documentation
near the constructor to describe this limit-enforced behavior.
- Around line 270-275: Update the pending-job refill flow around
fetch_new_job_rows so it retrieves eligible jobs in bounded pages rather than
loading and retaining the entire backlog in pending_job_queue. Add durable
paging state, such as a cursor that advances only after successful processing or
equivalent recovery-safe state, and preserve first-fetch recovery semantics so
retries resume without skipping jobs or causing unbounded memory growth.

In `@components/package-template/src/etc/clp-config.template.json.yaml`:
- Line 72: Update the commented max_concurrent_tasks configuration entry in the
template to explicitly state that its value must be greater than zero,
distinguishing it from compression_scheduler.max_concurrent_tasks_per_job where
zero disables the limit.
- Line 67: Update the compression coordinator configuration note near the
“Compression coordinator config” comment to document every runtime prerequisite:
`spider`, `logs_input.type: s3`, and `archive_output.storage.type: s3`; clarify
that the related template examples must use these required S3 settings rather
than `fs` when enabling the configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8fd3f43d-d433-437d-ab55-235ab39cfb5f

📥 Commits

Reviewing files that changed from the base of the PR and between 155fbda and e083517.

📒 Files selected for processing (4)
  • components/clp-py-utils/clp_py_utils/clp_config.py
  • components/clp-rust-utils/src/clp_config/package/config.rs
  • components/compression-coordinator/src/coordination.rs
  • components/package-template/src/etc/clp-config.template.json.yaml

Comment thread components/clp-py-utils/clp_py_utils/clp_config.py
Comment thread components/compression-coordinator/src/coordination.rs
Comment on lines +270 to +275
if self.pending_job_queue.is_empty() && self.job_handler_sem.available_permits() > 0 {
let new_job_rows = self.fetch_new_job_rows().await.inspect_err(|e| {
tracing::error!(error = % e, "Failed to fetch new jobs from database.");
})?;
self.pending_job_queue.extend(new_job_rows);
}

@coderabbitai coderabbitai Bot Aug 1, 2026

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.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Bound the pending-job queue.

fetch_new_job_rows returns every eligible database row, and this code retains every row and serialized CLP I/O configuration in pending_job_queue. A large backlog can still cause unbounded memory growth.

Fetch jobs in bounded pages. Preserve the first-fetch recovery semantics with a durable cursor or equivalent paging state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/compression-coordinator/src/coordination.rs` around lines 270 -
275, Update the pending-job refill flow around fetch_new_job_rows so it
retrieves eligible jobs in bounded pages rather than loading and retaining the
entire backlog in pending_job_queue. Add durable paging state, such as a cursor
that advances only after successful processing or equivalent recovery-safe
state, and preserve first-fetch recovery semantics so retries resume without
skipping jobs or causing unbounded memory growth.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We currently only fetch new jobs when the pending queue has been exhausted. so it's not like we will accumulate a backlog or get any duplicated pending jobs.
also this PR is about the limit for tokio spawns.
if you want to do paged fetches that's another story.

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.

@Bill-hbrhbr, agreed that this change correctly limits concurrent Tokio job-handler tasks.

The queue does not accumulate across refills. However, fetch_new_job_rows still loads all eligible rows during one refill, so one large backlog can make pending_job_queue large.

Paged fetching is separate from this PR’s scope. Would you like me to create a follow-up GitHub issue for bounded job fetching?

🐇💭

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LinZhihao-723 do we need bounded job fetching

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I thought it's a part of the plan.

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.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

# port: 6000
# logging_level: "INFO"
#
## Compression coordinator config. When set, the `spider` config below must also be set.

@coderabbitai coderabbitai Bot Aug 1, 2026

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Document all required runtime prerequisites.

components/compression-coordinator/src/bin/compression_coordinator.rs requires logs_input.type and archive_output.storage.type to be s3, in addition to requiring spider. The template examples use fs at Lines [29-34] and [150-155]. The new note names only spider, so enabling this configuration can still produce a startup error. Update the note at Line [67].

Proposed documentation update
-## Compression coordinator config. When set, the `spider` config below must also be set.
+## Compression coordinator config. When enabled, set the `spider` config below and use
+## S3 for `logs_input.type` and `archive_output.storage.type`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Compression coordinator config. When set, the `spider` config below must also be set.
## Compression coordinator config. When enabled, set the `spider` config below and use
## S3 for `logs_input.type` and `archive_output.storage.type`.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/package-template/src/etc/clp-config.template.json.yaml` at line
67, Update the compression coordinator configuration note near the “Compression
coordinator config” comment to document every runtime prerequisite: `spider`,
`logs_input.type: s3`, and `archive_output.storage.type: s3`; clarify that the
related template examples must use these required S3 settings rather than `fs`
when enabling the configuration.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will implement fs output in the near future. check docstring for other wording updates.

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.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

entrypoint=$(fd -t f '^compression_coordinator\.rs$' components)
if [ -n "$entrypoint" ]; then
  ast-grep outline "$entrypoint" --items all
  rg -n -C 5 --glob '*.rs' \
    '(logs_input|archive_output|storage\.type|compression_coordinator|Spider|spider|S3|s3)' \
    "$(dirname "$entrypoint")"
fi

rg -n -C 4 --glob '*.{rs,md,rst,yaml,yml,json}' \
  '(requires? .*s3|requires? .*S3|archive_output.*s3|logs_input.*s3|compression coordinator config)' \
  components

Length of output: 13354


@Bill-hbrhbr, I checked the runtime validation. The coordinator currently rejects non-S3 logs_input and non-S3 archive_output.storage. It also requires spider.

The template should describe the current restriction and allow a future filesystem-output change:

## Compression coordinator config. Currently requires `logs_input.type` and
## `archive_output.storage.type` to be "s3", and `spider` to be set.

I will keep the finding open because the current wording omits the archive-output requirement.


✏️ Learnings added
Learnt from: Bill-hbrhbr
Repo: y-scope/clp PR: 2435
File: components/package-template/src/etc/clp-config.template.json.yaml:0-0
Timestamp: 2026-08-01T09:17:11.203Z
Learning: The Rust compression coordinator currently supports only S3 log inputs and S3 archive outputs. Filesystem archive output is planned for a future implementation, so configuration documentation should state the S3 restriction as a current limitation.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

Comment thread components/package-template/src/etc/clp-config.template.json.yaml Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/compression-coordinator/src/coordination.rs (1)

294-300: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Record a job as dispatched only after handler creation succeeds.

dispatched_job_ids.push(job_id) runs before configuration deserialisation and create_job_handle. If either operation fails, run still passes the ID to mark_jobs_dispatched. An Error::UnsupportedInputConfig job therefore receives dispatch_time without a coordinator handler, which removes it from the subsequent pending-job query and can interfere with the documented legacy-scheduler hand-off.

Move the push after create_job_handle returns Ok:

Proposed fix
 let job_id = job_row.id;
- dispatched_job_ids.push(job_id);

 let clp_io_config: ClpIoConfig =
     match BrotliMsgpack::deserialize(&job_row.serialized_clp_io_config) {
         Ok(clp_io_config) => clp_io_config,
         Err(e) => {
             ...
         }
     };

 let Ok(job_handle) = self.create_job_handle(job_id, clp_io_config).await else {
     continue;
 };
+dispatched_job_ids.push(job_id);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/compression-coordinator/src/coordination.rs` around lines 294 -
300, Move dispatched_job_ids.push(job_id) in the run flow to after configuration
deserialization and successful create_job_handle completion, so only jobs with a
coordinator handler are marked dispatched; preserve failure handling without
passing failed job IDs to mark_jobs_dispatched.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/package-template/src/etc/clp-config.template.json.yaml`:
- Line 67: Update the compression coordinator configuration note near the
existing logs_input.type and spider requirements to also state that
archive_output.storage.type must be "s3". Keep the documentation aligned with
the coordinator prerequisites and the archive output setting shown in the
template.

---

Outside diff comments:
In `@components/compression-coordinator/src/coordination.rs`:
- Around line 294-300: Move dispatched_job_ids.push(job_id) in the run flow to
after configuration deserialization and successful create_job_handle completion,
so only jobs with a coordinator handler are marked dispatched; preserve failure
handling without passing failed job IDs to mark_jobs_dispatched.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b74354c7-b2d8-4659-a5ac-82902ed1fabb

📥 Commits

Reviewing files that changed from the base of the PR and between e083517 and 46e219c.

📒 Files selected for processing (3)
  • components/compression-coordinator/src/coordination.rs
  • components/compression-coordinator/src/error.rs
  • components/package-template/src/etc/clp-config.template.json.yaml

# port: 6000
# logging_level: "INFO"
#
## Compression coordinator config. Requires `logs_input.type` to be "s3" and `spider` to be set.

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Document the archive output prerequisite.

Line [67] documents the logs_input.type: "s3" and spider requirements, but the coordinator also requires archive_output.storage.type: "s3". The template still shows "fs" for archive output at Lines [150-155]. If users enable this configuration with the template values, the coordinator fails during startup. Update this note to include the archive output requirement.

Proposed documentation update
-## Compression coordinator config. Requires `logs_input.type` to be "s3" and `spider` to be set.
+## Compression coordinator config. Requires `logs_input.type` and `archive_output.storage.type` to be "s3", and `spider` to be set.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/package-template/src/etc/clp-config.template.json.yaml` at line
67, Update the compression coordinator configuration note near the existing
logs_input.type and spider requirements to also state that
archive_output.storage.type must be "s3". Keep the documentation aligned with
the coordinator prerequisites and the archive output setting shown in the
template.

# port: 6000
# logging_level: "INFO"
#
## Compression coordinator config. Requires `logs_input.type` to be "s3" and `spider` to be set.

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.

We are removing Spider config from this file, as it is only used for docker compose.

Comment on lines +289 to +292
while !self.pending_job_queue.is_empty() {
let Ok(permit) = self.job_handler_sem.clone().try_acquire_owned() else {
break;
};

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.

Getting a semaphore in a busy loop is not a good design.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed offline, I think it should be fine: the performance overhead isn't that large though especially in this use case.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should update this config. The current compression coordinator only supports helm (k8s) deployment which doesn't use this template. We should update it when we have docker compose support ready,

job_polling_interval: Duration,
cancellation_token: CancellationToken,
job_handler_sem: Arc<Semaphore>,
pending_job_queue: VecDeque<PendingJobRowProjection>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we need this. Can you explain why we can't do the following instead:

  • On the main loop, fetch compression jobs with a limit and ID ordering (sth like SELECT * FROM t ORDER BY id ASC LIMIT 100;)
  • Get a permit before spawning the coroutine. The permit automatially drops itself if the coroutine exits, aborts, or crashed.
  • Let the semaphore to block coroutine creation implicitly. The main loop may be blocked, which is fine because it shouldn't push more jobs into Spider.

This should lead to the behavior we expect iiuc.

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.

3 participants