documentation/MSBuild-scheduler.md
The diagram below illustrates the key components and workflows of the MSBuild Scheduler system.
The SchedulableRequest is a crucial internal wrapper class in the MSBuild scheduler that manages the lifecycle of build requests. It tracks:
Think of BuildRequest as the "what" and SchedulableRequest as the "how" to build a project.
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 BuildRequestParent property in the SchedulableRequestThe parent request is blocked while its child request is executing. This is a fundamental aspect of MSBuild's dependency handling system. When a parent request determines it needs results from a child request, the following happens:
If parent is absent, a schedulable request has parentRequest = null.
Central controller that manages build requests:
SchedulableRequests to nodesTracks state of all SchedulableRequest
SchedulableRequest state transitionsHistorical build information
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".Project configuration storage
Build result storage
So the default scheduling algorithm varies based on:
Uses AssignUnscheduledRequestsFIFO (First-In-First-Out)
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:
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:
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.
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.
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.
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.
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.
Prioritizes projects with smaller source file sizes. This can be useful when you want to complete many small projects quickly before tackling larger ones.
Prioritizes projects with larger source file sizes. This assumes that larger project files may take longer to build and schedules them earlier.
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.
Similar to WithMaxWaitingRequests, but only considers direct dependencies rather than the full transitive closure of waiting requests.
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.