feat: add network IO pressure and per-group concurrency limiting#7
Merged
Conversation
Add network bandwidth monitoring alongside existing disk IO tracking, with a new NetworkPressure backpressure source and budget-based admission gating. Introduce group-based concurrency limits so tasks targeting the same resource (e.g. an S3 endpoint) can be throttled independently from the global concurrency cap.
…currency Update README, feature docs, quick-start, IO/backpressure guide, progress reporting, and inline doc comments to cover network-aware scheduling, NetworkPressure, and per-group concurrency limits.
Merged
This was referenced Mar 14, 2026
deepjoy
pushed a commit
that referenced
this pull request
Mar 14, 2026
## 🤖 New release
* `taskmill`: 0.2.0 -> 0.3.0 (⚠ API breaking changes)
### ⚠ `taskmill` breaking changes
```text
--- failure constructible_struct_adds_field: externally-constructible struct adds field ---
Description:
A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field.
ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/constructible_struct_adds_field.ron
Failed in:
field TaskHistoryRecord.label in /tmp/.tmpgCrMRt/taskmill/src/task.rs:147
field TaskHistoryRecord.expected_net_rx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:154
field TaskHistoryRecord.expected_net_tx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:156
field TaskHistoryRecord.actual_net_rx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:160
field TaskHistoryRecord.actual_net_tx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:162
field TaskHistoryRecord.group_key in /tmp/.tmpgCrMRt/taskmill/src/task.rs:174
field TaskHistoryRecord.label in /tmp/.tmpgCrMRt/taskmill/src/task.rs:147
field TaskHistoryRecord.expected_net_rx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:154
field TaskHistoryRecord.expected_net_tx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:156
field TaskHistoryRecord.actual_net_rx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:160
field TaskHistoryRecord.actual_net_tx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:162
field TaskHistoryRecord.group_key in /tmp/.tmpgCrMRt/taskmill/src/task.rs:174
field EstimatedProgress.label in /tmp/.tmpgCrMRt/taskmill/src/scheduler/progress.rs:95
field EstimatedProgress.label in /tmp/.tmpgCrMRt/taskmill/src/scheduler/progress.rs:95
field EstimatedProgress.label in /tmp/.tmpgCrMRt/taskmill/src/scheduler/progress.rs:95
field TaskRecord.label in /tmp/.tmpgCrMRt/taskmill/src/task.rs:99
field TaskRecord.expected_net_rx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:106
field TaskRecord.expected_net_tx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:108
field TaskRecord.group_key in /tmp/.tmpgCrMRt/taskmill/src/task.rs:123
field TaskRecord.label in /tmp/.tmpgCrMRt/taskmill/src/task.rs:99
field TaskRecord.expected_net_rx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:106
field TaskRecord.expected_net_tx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:108
field TaskRecord.group_key in /tmp/.tmpgCrMRt/taskmill/src/task.rs:123
field ResourceSnapshot.net_rx_bytes_per_sec in /tmp/.tmpgCrMRt/taskmill/src/resource/mod.rs:34
field ResourceSnapshot.net_tx_bytes_per_sec in /tmp/.tmpgCrMRt/taskmill/src/resource/mod.rs:36
field ResourceSnapshot.net_rx_bytes_per_sec in /tmp/.tmpgCrMRt/taskmill/src/resource/mod.rs:34
field ResourceSnapshot.net_tx_bytes_per_sec in /tmp/.tmpgCrMRt/taskmill/src/resource/mod.rs:36
field TaskSubmission.dedup_key in /tmp/.tmpgCrMRt/taskmill/src/task.rs:332
field TaskSubmission.label in /tmp/.tmpgCrMRt/taskmill/src/task.rs:335
field TaskSubmission.expected_net_rx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:341
field TaskSubmission.expected_net_tx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:343
field TaskSubmission.group_key in /tmp/.tmpgCrMRt/taskmill/src/task.rs:357
field TaskSubmission.dedup_key in /tmp/.tmpgCrMRt/taskmill/src/task.rs:332
field TaskSubmission.label in /tmp/.tmpgCrMRt/taskmill/src/task.rs:335
field TaskSubmission.expected_net_rx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:341
field TaskSubmission.expected_net_tx_bytes in /tmp/.tmpgCrMRt/taskmill/src/task.rs:343
field TaskSubmission.group_key in /tmp/.tmpgCrMRt/taskmill/src/task.rs:357
--- failure enum_struct_variant_field_added: pub enum struct variant field added ---
Description:
An enum's exhaustive struct variant has a new field, which has to be included when constructing or matching on this variant.
ref: https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_struct_variant_field_added.ron
Failed in:
field label of variant SchedulerEvent::Dispatched in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:82
field label of variant SchedulerEvent::Completed in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:89
field label of variant SchedulerEvent::Failed in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:96
field label of variant SchedulerEvent::Preempted in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:105
field label of variant SchedulerEvent::Cancelled in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:112
field label of variant SchedulerEvent::Progress in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:119
field label of variant SchedulerEvent::Dispatched in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:82
field label of variant SchedulerEvent::Completed in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:89
field label of variant SchedulerEvent::Failed in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:96
field label of variant SchedulerEvent::Preempted in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:105
field label of variant SchedulerEvent::Cancelled in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:112
field label of variant SchedulerEvent::Progress in /tmp/.tmpgCrMRt/taskmill/src/scheduler/mod.rs:119
--- failure inherent_method_missing: pub method removed or renamed ---
Description:
A publicly-visible method or associated fn is no longer available under its prior name. It may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/inherent_method_missing.ron
Failed in:
TaskContext::deserialize_typed, previously in file /tmp/.tmpuPxM8D/taskmill/src/registry.rs:157
TaskContext::deserialize_typed, previously in file /tmp/.tmpuPxM8D/taskmill/src/registry.rs:157
--- failure method_parameter_count_changed: pub method parameter count changed ---
Description:
A publicly-visible method now takes a different number of parameters, not counting the receiver (self) parameter.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#fn-change-arity
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/method_parameter_count_changed.ron
Failed in:
taskmill::store::TaskStore::fail now takes 5 parameters instead of 6, in /tmp/.tmpgCrMRt/taskmill/src/store.rs:591
taskmill::TaskStore::fail now takes 5 parameters instead of 6, in /tmp/.tmpgCrMRt/taskmill/src/store.rs:591
--- failure struct_missing: pub struct removed or renamed ---
Description:
A publicly-visible struct cannot be imported by its prior path. A `pub use` may have been removed, or the struct itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/struct_missing.ron
Failed in:
struct taskmill::task::TaskResult, previously in file /tmp/.tmpuPxM8D/taskmill/src/task.rs:151
struct taskmill::TaskResult, previously in file /tmp/.tmpuPxM8D/taskmill/src/task.rs:151
--- failure struct_pub_field_missing: pub struct's pub field removed or renamed ---
Description:
A publicly-visible struct has at least one public field that is no longer available under its prior name. It may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/struct_pub_field_missing.ron
Failed in:
field actual_read_bytes of struct TaskError, previously in file /tmp/.tmpuPxM8D/taskmill/src/task.rs:161
field actual_write_bytes of struct TaskError, previously in file /tmp/.tmpuPxM8D/taskmill/src/task.rs:162
field actual_read_bytes of struct TaskError, previously in file /tmp/.tmpuPxM8D/taskmill/src/task.rs:161
field actual_write_bytes of struct TaskError, previously in file /tmp/.tmpuPxM8D/taskmill/src/task.rs:162
field key of struct TaskSubmission, previously in file /tmp/.tmpuPxM8D/taskmill/src/task.rs:222
field key of struct TaskSubmission, previously in file /tmp/.tmpuPxM8D/taskmill/src/task.rs:222
field record of struct TaskContext, previously in file /tmp/.tmpuPxM8D/taskmill/src/registry.rs:140
field token of struct TaskContext, previously in file /tmp/.tmpuPxM8D/taskmill/src/registry.rs:143
field progress of struct TaskContext, previously in file /tmp/.tmpuPxM8D/taskmill/src/registry.rs:145
field record of struct TaskContext, previously in file /tmp/.tmpuPxM8D/taskmill/src/registry.rs:140
field token of struct TaskContext, previously in file /tmp/.tmpuPxM8D/taskmill/src/registry.rs:143
field progress of struct TaskContext, previously in file /tmp/.tmpuPxM8D/taskmill/src/registry.rs:145
--- failure struct_pub_field_now_doc_hidden: pub struct field is now #[doc(hidden)] ---
Description:
A pub field of a pub struct is now marked #[doc(hidden)] and is no longer part of the public API.
ref: https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html#hidden
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/struct_pub_field_now_doc_hidden.ron
Failed in:
field TaskContext.record in file /tmp/.tmpgCrMRt/taskmill/src/registry.rs:182
field TaskContext.token in file /tmp/.tmpgCrMRt/taskmill/src/registry.rs:182
field TaskContext.progress in file /tmp/.tmpgCrMRt/taskmill/src/registry.rs:182
field TaskContext.record in file /tmp/.tmpgCrMRt/taskmill/src/registry.rs:182
field TaskContext.token in file /tmp/.tmpgCrMRt/taskmill/src/registry.rs:182
field TaskContext.progress in file /tmp/.tmpgCrMRt/taskmill/src/registry.rs:182
```
<details><summary><i><b>Changelog</b></i></summary><p>
<blockquote>
## [0.3.0](v0.2.0...v0.3.0)
- 2026-03-14
### Added
- add network IO pressure and per-group concurrency limiting
([#7](#7))
### Other
- [**breaking**] builder pattern for TaskSubmission and accessor methods
for TaskContext ([#6](#6))
- [**breaking**] simplify executor API with incremental IO tracking and
expanded docs ([#4](#4))
</blockquote>
</p></details>
---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TaskSubmission::expected_net_io()(andTypedTask::expected_net_rx_bytes/expected_net_tx_bytes). Executors report actuals viaTaskContext::record_net_rx_bytes()/record_net_tx_bytes(). Network metrics are persisted in bothtasksandtask_historytables.NetworkPressuresource maps observed RX+TX throughput (viasysinfo) against a configurable bandwidth cap to produce backpressure. Enable withSchedulerBuilder::bandwidth_limit(bytes_per_sec). TheSysinfoSamplernow tracks aggregate network interface throughput alongside CPU and disk.TaskSubmission::group(key)(orTypedTask::group_key()). The scheduler enforces per-group concurrency limits independent of globalmax_concurrency. Configure at build time with.group_concurrency(group, limit)/.default_group_concurrency(n), or adjust at runtime viaset_group_limit()/remove_group_limit()/set_default_group_concurrency().Changes
ResourceSnapshotgainsnet_rx_bytes_per_sec/net_tx_bytes_per_secfields; EWMA smoothing applied in sampler loopSysinfoSamplertracksNetworksalongsideDisksfor cross-platform network throughputresource::network_pressuremodule withNetworkPressureimplementingPressureSourceTaskRecord,TaskHistoryRecord,TaskSubmission,TaskMetricsgain network IO andgroup_keyfieldsTaskContextgainsrecord_net_rx_bytes()/record_net_tx_bytes()(viaIoTracker)DefaultDispatchGateadds network IO budget check (has_net_io_headroom) and group concurrency checkGroupLimitsstruct (atomic default +RwLock<HashMap>overrides) exposed onSchedulerSchedulerBuildergainsbandwidth_limit(),default_group_concurrency(),group_concurrency()methodsTaskStoregainsrunning_net_io_totals()andrunning_count_for_group()queries003_net_io_and_groups.sqladds net IO columns,group_key, and a partial indexTypedTasktrait gainsexpected_net_rx_bytes(),expected_net_tx_bytes(), andgroup_key()defaults