Skip to content

Add agave-scheduler-bindings crate#7823

Merged
apfitzge merged 17 commits intoanza-xyz:masterfrom
apfitzge:scheduler-bindings-messages
Sep 23, 2025
Merged

Add agave-scheduler-bindings crate#7823
apfitzge merged 17 commits intoanza-xyz:masterfrom
apfitzge:scheduler-bindings-messages

Conversation

@apfitzge
Copy link
Copy Markdown

@apfitzge apfitzge commented Sep 2, 2025

Problem

  • scheduler-bindings relies on passing messages between external-pack, tpu, workers, etc.

Summary of Changes

  • Add message types and constants for scheduler-bindings
  • These are NOT complete, and some additional flags, tags, etc will be added as additional features are added. These represent a near-minimal set of message types for a functional external pack process to be run and communicate with agave to produce blocks

Fixes #

@apfitzge apfitzge force-pushed the scheduler-bindings-messages branch 4 times, most recently from f8a3896 to ec77626 Compare September 2, 2025 15:24
pub transactions: [SharableTransaction; MAX_TRANSACTIONS_PER_PACK_MESSAGE],
}

pub mod pack_message_flags {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Flags for supporting bundles:

  • DROP_ON_FAILURE
  • ALL_OR_NONE
    will be added here once the functionality is supported.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Additional flags for:

  • checking balance
  • checking status (already processed or not)

outside of any slot (similar to RESOLVE) will also likely be added

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Granularity is great but in general I think any scheduler is interested in 'is this still valid' so that includes basically everything in recv_and_buffer; If can enumerate everything separately; great; might never be used individually though

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

yeah, i'm planning to add the checking balance and status here as mentioned above. but it'll likely support having all 3 flags set to check/perform all of them.

@apfitzge apfitzge force-pushed the scheduler-bindings-messages branch from ec77626 to 8f8a871 Compare September 2, 2025 15:34
@apfitzge apfitzge changed the title agave-scheduler-bindings Add agave-scheduler-bindings crate Sep 2, 2025
Comment thread scheduler-bindings/src/lib.rs Outdated
pub num_transactions: u8,
/// Transactions in the message. Only the first `num_transactions`
/// entries are valid to read.
pub transactions: [SharableTransaction; MAX_TRANSACTIONS_PER_PACK_MESSAGE],
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thought about making this an allocation from the external pack, which would allow us an arbitrary number of txs per message.
But I don't think there's enough value in that vs the static sized array to avoid additional indirection.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We could start with variable length txs if unsure MAX_TRANSACTIONS_PER_PACK_MESSAGE will change often in the future.

@apfitzge apfitzge marked this pull request as ready for review September 2, 2025 16:38
@apfitzge apfitzge requested a review from tao-stones September 2, 2025 16:38
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Sep 2, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.0%. Comparing base (b8dba5a) to head (7cb9c3a).
⚠️ Report is 1748 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##           master    #7823     +/-   ##
=========================================
- Coverage    83.0%    83.0%   -0.1%     
=========================================
  Files         808      808             
  Lines      356265   356265             
=========================================
- Hits       296043   296006     -37     
- Misses      60222    60259     +37     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread scheduler-bindings/src/lib.rs Outdated
/// begins.
pub progress: i16,
/// The number of compute units packed in the current block, if leader.
pub total_compute_units: u64,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Should this be total_compute_units_left? Signals capacity (easier forward compatibility for CU Limit increases)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

That's a great idea!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

made it remaining_cost_units since these are actually cost_units not compute_units 😬

/// Message: [Worker -> Pack]
/// Message from worker threads in response to a [`PackToWorkerMessage`].
/// [`PackToWorkerMessage`] may have multiple response messages that
/// will follow the order of transactions in the original message.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Might be easier to reason about things if the response message contains results for everything in one 'batch'

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

the actual message types here are somewhat large, if we had a static array of the tagged-unions, total batch size would be 2048 bytes. If doing small batch sizes of say 3 messages (bundles) then the messages would be 90% useless. Effectively that would make it necessary to increase the size of the queue to accomodate smaller batches.

While the responses for each tx are in different messages, agave will always commit them as a batch. i.e. if you sent a batch of 10 txs, you will not receive 8 of the responses but not the last 2; it's always 10 or none that are visible (the shared queue writer position) to the external scheduler.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

if all possible, would be great to stick with one response per request. Speak of which, is Packer expected to have a timer or something when wait for response from Workers, or it will hold on to original message/txs until response is received?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

if all possible, would be great to stick with one response per request.

See comment above - it's possible but wastes an incredible amount of space or causes additional indirection. It's a loop either way, this is a simpler approach that creating a pointer which then needs to be freed.

expected to have a timer

Not sure what value having a timer would have, wdym? Pack sends messages with transactions, worker will respond in order.

or it will hold on to original message/txs until response is received?

It doesn't need to hold onto anything from the original message, except ALT pubkey ptrs if it doesn't want to re-resolve for unlocking the keys in it's internal lock-tracking (if any).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

what packer should do in case worker never responded (due to unexpected cause)?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

If it never responds or responds in a different order it indicates a bug in the worker. So it'd probably be reasonable to shutdown the external scheduler to let agave fall back to internal scheduler, or to make that switch manually.

Comment thread scheduler-bindings/src/lib.rs Outdated
/// If [`pack_message_flags::RESOLVE`] flag is not set, this is the slot
/// the transactions can be processed in. If the flag is set to
/// [`ANY_SLOT`], the transactions can be processed in any slot in agave.
pub slot: u64,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could be max_slot for flexibility

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🤔 yeah that seems reasonable. then I don't even need to declare ANY_SLOT as a special flag...that's implied!

Comment thread scheduler-bindings/src/lib.rs Outdated
/// The transaction that was included.
pub transaction: SharableTransaction,
/// Compute units used by the transaction.
pub compute_units: u64,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think need account_data_size_loaded too for proper CostModel updates

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

yeah this should be cost-units not compute-units

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CUs vs CUs 😵

Comment thread scheduler-bindings/src/lib.rs Outdated

/// Reference to a transaction that can shared safely across processes.
#[repr(C)]
pub struct SharableTransaction {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: I found calling it "...Transaction" is bit misleading, and we have so many "transaction" types already. What do you think call it "SharableTransactionRegion" or "SharableTransactionDescriptor"?

Comment thread scheduler-bindings/src/lib.rs
Comment thread scheduler-bindings/src/lib.rs
Comment thread scheduler-bindings/src/lib.rs
Comment thread scheduler-bindings/src/lib.rs Outdated
Comment thread scheduler-bindings/src/lib.rs Outdated
/// Message: [Worker -> Pack]
/// Message from worker threads in response to a [`PackToWorkerMessage`].
/// [`PackToWorkerMessage`] may have multiple response messages that
/// will follow the order of transactions in the original message.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

if all possible, would be great to stick with one response per request. Speak of which, is Packer expected to have a timer or something when wait for response from Workers, or it will hold on to original message/txs until response is received?

Comment thread scheduler-bindings/src/lib.rs
Comment thread scheduler-bindings/src/lib.rs Outdated
/// the transaction will not be processed.
pub max_execution_slot: u64,
/// The number of transactions in this message.
/// MUST be in the range [1, [`MAX_TRANSACTIONS_PER_PACK_MESSAGE`]].
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

How do you think to implement basic validation alone with message type def?

"max_execution_slot MUST be in the range [1, [MAX_TRANSACTIONS_PER_PACK_MESSAGE]]" is a good example for impl MessageValidation for PackToWorkerMessage {...}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'm really not sure what you mean. It'll be an if statement lol

Copy link
Copy Markdown
Author

@apfitzge apfitzge Sep 6, 2025

Choose a reason for hiding this comment

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

Oh I see what you mean, you mean have validation inside this file.

I'm against that. I've intentionally kept any functions out of this file, it is intended only as type definitions.

edit: This file is intended to be a defintion of the binary interface. Any functionality should not be in here imo.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

yea, I see your point. Ideally the message type doesn't have such subtle inner logic. Maybe it can be a reason to remove MAX_TRANSACTIONS_PER_PACK_MESSAGE, have Packer to dynamically reserve transactions?

Comment thread scheduler-bindings/src/lib.rs Outdated
pub num_transactions: u8,
/// Transactions in the message. Only the first `num_transactions`
/// entries are valid to read.
pub transactions: [SharableTransaction; MAX_TRANSACTIONS_PER_PACK_MESSAGE],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We could start with variable length txs if unsure MAX_TRANSACTIONS_PER_PACK_MESSAGE will change often in the future.

@apfitzge apfitzge force-pushed the scheduler-bindings-messages branch from 7696b96 to 8125c7c Compare September 8, 2025 16:51
Copy link
Copy Markdown

@tao-stones tao-stones left a comment

Choose a reason for hiding this comment

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

Thanks for explaining and updating, it looks so much better 🔥

Wondering your think on this, in case for some reason, Workers got backed up, Packer can't release Transactions, then can cascade to TPU can't reserve space for new Transaction. Add a TTL field to Pack->Work message can help in that particular case. wdyt?

@apfitzge
Copy link
Copy Markdown
Author

apfitzge commented Sep 9, 2025

Wondering your think on this, in case for some reason, Workers got backed up, Packer can't release Transactions, then can cascade to TPU can't reserve space for new Transaction. Add a TTL field to Pack->Work message can help in that particular case. wdyt?

Yeah there will be some logic inside of agave to fall back to an internal scheduler.
If we cannot reserve messages in queues, if we cannot allocate space in transactions, etc.
Set a signal to shutdown the threads, and then BS will respawn with the default scheduler.

@apfitzge apfitzge force-pushed the scheduler-bindings-messages branch from 520ae84 to 1be3ecf Compare September 9, 2025 14:57
@apfitzge apfitzge requested a review from tao-stones September 11, 2025 22:02
Copy link
Copy Markdown

@tao-stones tao-stones left a comment

Choose a reason for hiding this comment

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

thanks for documenting the workflows 👍🏼

Comment thread scheduler-bindings/src/lib.rs
Comment thread scheduler-bindings/src/lib.rs Outdated
/// this offset. The type of each inner message is indicated by `tag`.
/// There are `num_transaction_responses` inner messages.
/// See [`worker_message_types`] for details on the inner message types.
pub transaction_responses_offset: u32,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: to keep the existing pattern elsewhere, these two fields can be defined as a "region"?

struct TransactionResponseRegion {
    transaction_responses_offset: u32, 
    num_transaction_responses: u8,
}

Copy link
Copy Markdown

@tao-stones tao-stones left a comment

Choose a reason for hiding this comment

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

The Packer ↔ Worker flow is much clearer now. Let me try to summarize it:

  1. Packer → Worker: sends a TransactionBatchRegion, with process instructions such as vanilla execution (None) or resolve.

  2. Expectation: Packer expects a single response message from Worker.

  3. Worker → Packer: replies with the same TransactionBatchRegion (so Packer doesn’t need to retain a local copy) along with a ResponseRegion. The reply indicates whether the original Packer2Worker message was invalid, or, if valid, provides per-transaction processing results.

Hope that's accurate?

Comment thread scheduler-bindings/src/lib.rs Outdated
/// Tag indicating the type of message.
/// See [`worker_message_types`] for details.
/// If the tag is [`worker_message_types::INVALID_MESSAGE`],
/// no inner messages will be present and `num_transaction_responses`
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

note: would be useful to provide reasons of why original Packer2Worker message was invalid?

Comment thread scheduler-bindings/src/lib.rs
Comment thread scheduler-bindings/src/lib.rs Outdated
Comment thread scheduler-bindings/src/lib.rs Outdated
/// Tag indicating [`InvalidMessage`] inner message.
/// Tag indicating the sent message was invalid.
/// No inner messages will be present.
pub const INVALID_MESSAGE: u8 = 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

per early suggestion, this can be removed


pub mod not_included_reasons {
/// The transaction was included in the block - i.e. no reason it was not included.
pub const NONE: u8 = 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nerdy nit: the double negative ("no reason it was not included" == "included, cost_units and fee_payer_balance can be looked at"). I don't know what's good way to straight it out without adding an additional field.

@apfitzge apfitzge force-pushed the scheduler-bindings-messages branch from def658d to 7cb9c3a Compare September 12, 2025 20:11
@apfitzge apfitzge requested a review from tao-stones September 22, 2025 16:22
Copy link
Copy Markdown

@tao-stones tao-stones left a comment

Choose a reason for hiding this comment

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

thanks for addressing all the comments. it looks great

@apfitzge apfitzge merged commit 1140c26 into anza-xyz:master Sep 23, 2025
54 checks passed
@apfitzge apfitzge deleted the scheduler-bindings-messages branch September 23, 2025 21:08
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