-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add docs about Scheduler #11672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
YuliiaKovalova
merged 6 commits into
dotnet:main
from
YuliiaKovalova:dev/ykovalova/add_docs_about_scheduling
Jun 5, 2025
Merged
Add docs about Scheduler #11672
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
7cb2088
add scheduler overview
YuliiaKovalova fce8e88
markup cleanup
YuliiaKovalova 3bfd579
Apply suggestions from code review
YuliiaKovalova 1923844
the document content adjustment
YuliiaKovalova d548123
Merge branch 'dev/ykovalova/add_docs_about_scheduling' of https://git…
YuliiaKovalova 9c06998
Update MSBuild-scheduler.md
YuliiaKovalova File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| # MSBuild Scheduler Architecture | ||
|
|
||
| The diagram below illustrates the key components and workflows of the MSBuild Scheduler system. | ||
|
|
||
|  | ||
|
|
||
| ## Request Lifecycle | ||
|
|
||
| ### 1. Submission | ||
| - BuildManager generates root request to the Scheduler | ||
| - Configuration is registered and SchedulableRequest is created | ||
|
|
||
| ### 2. Scheduling | ||
| - Scheduler applies algorithm to select node for request | ||
| - Request is assigned to node and moves to Executing state | ||
|
|
||
| ### 3. Execution | ||
| - Node processes request and may encounter dependencies | ||
| - If blocked, node reports to Scheduler with blocker information | ||
| - Scheduler creates new requests for dependencies and schedules them | ||
|
|
||
| ### 4. Completion | ||
| - Node reports build results back to Scheduler | ||
| - Results are cached and request is marked complete | ||
| - Parent requests are unblocked with results | ||
|
|
||
| ### 5. Result Processing | ||
| - Results propagate through dependency chain | ||
| - When all requests complete, submission is reported complete | ||
|
|
||
| ## Core Components | ||
|
|
||
| ### SchedulableRequest | ||
| The SchedulableRequest is a crucial internal wrapper class in the MSBuild scheduler that manages the lifecycle of build requests. | ||
| It tracks: | ||
|
|
||
| - The current state of the request (Unscheduled, Executing, Blocked, Ready, Yielding, Completed) | ||
| - Which node it's assigned to | ||
| - The relationships to other requests (parent/child or blocking/blocked-by) | ||
| - Timing and execution details | ||
|
|
||
| Think of `BuildRequest` as the "what" and `SchedulableRequest` as the "how" to build a project. | ||
YuliiaKovalova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| #### When does SchedulableRequest have a parent? | ||
| In MSBuild, builds often have dependencies. When a project needs to build another project first, it creates a child request. | ||
| The original one becomes the "parent request" of this new child request. | ||
| For example: | ||
|
|
||
| `ProjectA` is building (parent request) => `ProjectA` references `ProjectB`, so it creates a request to build `ProjectB` (child request) => `ProjectA's` request is considered the "parent request" of `ProjectB's` request | ||
|
|
||
| This parent-child relationship is tracked through: | ||
| - `ParentGlobalRequestId` in the `BuildRequest` | ||
| - The `Parent` property in the `SchedulableRequest` | ||
|
|
||
| The parent request is blocked while its child request is executing. This is a fundamental aspect of MSBuild's dependency handling system. | ||
YuliiaKovalova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| When a parent request determines it needs results from a child request, the following happens: | ||
|
|
||
| 1) The parent request enters the "Blocked" state | ||
| 2) The scheduler creates the child request | ||
| 3) The parent remains blocked until the child completes | ||
| 4) Once the child request finishes, its results are returned to the parent | ||
| 5) The parent moves from "Blocked" to "Ready" state | ||
| 6) The scheduler can then resume executing the parent request | ||
|
|
||
|  | ||
|
|
||
| If parent is absent, a schedulable request has `parentRequest = null`. | ||
|
|
||
| ### Scheduler | ||
| Central controller that manages build requests: | ||
| - Assigns `SchedulableRequests` to nodes | ||
| - Handles blocking and unblocking requests | ||
| - Checks if the result can be satisfied from the MSBuild cache | ||
|
|
||
| ### SchedulingData | ||
| Tracks state of all `SchedulableRequest` | ||
| - Request `SchedulableRequest` state transitions | ||
| - Node assignments | ||
| - Configuration tracking | ||
|
|
||
| ### SchedulingPlan | ||
| Historical build information | ||
| - Project references | ||
| - Build times | ||
| - Configuration mappings | ||
| This data can then be used by subsequent builds to determine how best to distribute work among several nodes. | ||
|
|
||
| ## Request Management | ||
|
|
||
| ### BuildRequest | ||
| Basic representation of build operation | ||
| - `GlobalRequestId`: A unique identifier for the request across the entire build session. This ID stays constant regardless of which node processes the request. It allows the scheduler to track and reference the request throughout the build lifecycle. If two requests are semantically identical (same targets for the same project **configuration**), they may share the same GlobalRequestId to enable result reuse. | ||
| - `ConfigurationId`: Identifies which project configuration this request is for. A configuration represents a unique combination of project file + global properties + tools version. | ||
| - `NodeRequestId`: A node-specific identifier for the request. Each node maintains its own request IDs, which are used for local tracking on that node (whether in-process or out-of-process). | ||
| - `SubmissionId`: an identifier that groups related BuildRequests that originate from a single top-level build command or operation. | ||
| - `ParentGlobalRequestId`: References the GlobalRequestId of the request that created this one. For example, if ProjectA depends on ProjectB, the request to build ProjectB would have ProjectA's request ID as its ParentGlobalRequestId. This allows the scheduler to track dependencies and manage the build process effectively. | ||
| - `Targets`: The list of targets to build in this project. These are the specific build tasks to execute, like "Clean", "Build", or "Publish". | ||
|
|
||
| ## Caching System | ||
|
|
||
| ### ConfigCache | ||
| Project configuration storage | ||
| - Project files | ||
| - Global properties | ||
| - Targets | ||
| - ToolsVersion | ||
|
|
||
| ### ResultsCache | ||
| Build result storage | ||
| - Target outputs | ||
| - Build success/failure | ||
| - Target-level granularity | ||
|
|
||
| ## Scheduling Algorithms | ||
|
|
||
| So the default scheduling algorithm varies based on: | ||
|
|
||
| ### Single-Processor Case (MaxNodeCount = 1): | ||
| Uses AssignUnscheduledRequestsFIFO (First-In-First-Out) | ||
|
|
||
| ### Multi-Processor Case (MaxNodeCount > 1): | ||
| - First calls AssignUnscheduledRequestsByTraversalsFirst to prioritize traversal projects | ||
| - Then calls AssignUnscheduledProxyBuildRequestsToInProcNode for proxy builds | ||
YuliiaKovalova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| - Then chooses based on whether a valid scheduling plan exists: | ||
|
|
||
| #### With Valid Plan: | ||
| - For 2 nodes: AssignUnscheduledRequestsWithPlanByMostImmediateReferences | ||
| - For 3+ nodes: AssignUnscheduledRequestsWithPlanByGreatestPlanTime | ||
|
|
||
| #### Without Valid Plan: | ||
| - AssignUnscheduledRequestsWithConfigurationCountLevelling | ||
|
|
||
| A "valid plan" in MSBuild refers to historical build data that was collected from previous successful builds and stored for optimization purposes. | ||
| A scheduling plan contains information about: | ||
|
|
||
| 1) Build Times: How long each project took to build | ||
| 2) Project References: Which projects reference other projects | ||
| 3) Configuration Maps: How project paths map to configuration IDs | ||
|
|
||
| This data is saved at the end of a successful build, typically in a file with extension `.buildplan`, so it can be used to make better scheduling decisions in future builds. To have this build plan generated, environment variable `MSBUILDENABLEBUILDPLAN` should be set with `true` value. | ||
|
|
||
| MSBuild supports multiple scheduling algorithms that can be selected via the `MSBUILDCUSTOMSCHEDULER` environment variable: | ||
|
|
||
| ### FIFO | ||
| First-come, first-served scheduling - assigns requests in the order they are received. This is the simplest algorithm and works well for single-processor scenarios. | ||
|
|
||
| ### ByTraversalsFirst | ||
| Prioritizes traversal projects (like solution files) to identify more work quickly. This algorithm identifies and schedules projects that reference many other projects first, helping to discover parallelization opportunities early in the build. | ||
|
|
||
| ### WithConfigurationCountLevelling | ||
| Balances configurations across nodes to distribute work evenly. This algorithm tries to ensure each node has approximately the same number of distinct project configurations, which can improve caching behavior. | ||
|
|
||
| ### WithPlanByMostImmediateReferences | ||
| Prioritizes projects with the most direct references to other projects. This requires a valid scheduling plan from a previous build and helps maximize parallelism by tackling projects with many dependencies first. | ||
YuliiaKovalova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### WithPlanByGreatestPlanTime | ||
| Uses historical build times to prioritize longer-running tasks. This requires a valid scheduling plan from a previous build and schedules the most time-consuming projects first to minimize overall build time. | ||
|
|
||
| ### WithSmallestFileSize | ||
| Prioritizes projects with smaller source file sizes. This can be useful when you want to complete many small projects quickly before tackling larger ones. | ||
|
|
||
| ### WithLargestFileSize | ||
| Prioritizes projects with larger source file sizes. This assumes that larger project files may take longer to build and schedules them earlier. | ||
|
|
||
| ### WithMaxWaitingRequests | ||
| Prioritizes requests that have the most other requests waiting on them, using the transitive closure of the dependency tree. This helps unblock the maximum number of dependent projects. | ||
|
|
||
| ### WithMaxWaitingRequests2 | ||
| Similar to WithMaxWaitingRequests, but only considers direct dependencies rather than the full transitive closure of waiting requests. | ||
|
|
||
| ### CustomSchedulerForSQL | ||
| Specialized algorithm for SQL builds to avoid node overloading. This algorithm intentionally limits the number of configurations assigned to any single node, which helps with builds that have many configurations that reference the same projects. It can be fine-tuned with the `MSBUILDCUSTOMSCHEDULERFORSQLCONFIGURATIONLIMITMULTIPLIER` environment variable. | ||
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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.
Uh oh!
There was an error while loading. Please reload this page.