-
Notifications
You must be signed in to change notification settings - Fork 128
🌍↔️🐍 Limit the number of simultaneous executions #2428
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
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 60717fc The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
bsipocz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much for fixing this. I have only have a few minor comments.
Co-authored-by: Brigitta Sipőcz <[email protected]>
agoose77
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@agahkarakuzu I think I'd like to change the approach here to use a semaphore, rather than limiting transforms of the pages. I am thinking of limiting execution as a particular example of concurrency control that differs from the general concurrent processing problem. A reasonable amount of transform work is network requests, so I'd like for those to remain in-flight where possible — and we probably want another setting for throttling concurrent fetch in future.
I can do the work to rework this to use e.g. https://www.npmjs.com/package/async-mutex, or if you have the capacity, feel free. The idea would be to pass the semaphore in to the transformMdast function, and use the runExclusive method to decorate the kernelExecutionTransform — I don't think concurrency is something that transform needs to worry about.
Longer term, we'll end up refactoring this to have some ExecutionOrchestrator handle this, but I think that relates to #2413.
|
@agoose77 that's indeed a cleaner solution and paves the way better for an orchestration approach. I'll give it a stab. |
|
What a star! ⭐ |
- Add debug level log info - Remove transformMdast limits (revert to original) - Pass options from commands to the session
|
@agoose77 I added
I am just not really sure if this is elegant or acceptable: const opts = { ...program.opts(), ...this.opts() } as SessionOpts;But I needed a way to pass |
docs/execute-notebooks.md
Outdated
| By default, up to {math}`N-1` executable files are run concurrently, where {math}`N` is the number of available CPUs. | ||
|
|
||
| You can change this by using the `--execute-parallel <n>` option in your build command, where `<n>` sets the maximum number of executable documents to run at once. For example, using `--execute-parallel 1` will run the documents one after another. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a short "this is useful when___" type of sentence so users know why they might want to do this?
packages/myst-cli/src/cli/options.ts
Outdated
| export function makeExecuteParallelOption() { | ||
| const defaultParallelism = Math.max(1, cpus().length - 1); | ||
| return new Option('--execute-parallel <n>', `Maximum number of notebooks to execute in parallel`) | ||
| .argParser(parseInt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will this ensure that --execute-parallel foo doesn't work? Should we test for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if --execute-parallel 0?
choldgraf
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks useful! Thanks for the contribution. My main suggestion is that we add some kind of testing (both for edge cases like --execute-parallel foo and to ensure it's actually doing what we think it is).
|
Thanks for the feedback @choldgraf, I’ve pushed updates to address your comments. Regarding testing, we could add three notebooks that each wait for about five seconds, then assert that the total build time is at least fifteen seconds when Since the transformations run in a non-deterministic order, it is not possible to create a test case where the output of one serves as the input to another. |
|
hmmm, could we make that more like .5 seconds each? I don't want to just auto-add 15 seconds to the test suite 😅 If nobody has better ideas for how to test this, I'd also be fine just leaving it and seeing if users complain about it or not |
|
I think the fastest robust way to do this is to use concurrency primitives like barrier and mutex. The easiest thing is probably to create these in a python process, and share their pickled representations via the filesystem or env vars. This would require a small addition to the test harness. We can then ensure that |
|
Testing this logic is a bit awkward because the implementation is at the end-to-end (E2E) level, rather than within the core execution package. This makes sense from a design standpoint, because the concept of dependencies and ordering is a higher level one than "execute this file". Unfortunately, to then test this is fiddly because we need to do so in a mostly stateless way. For now, it's possible to implement some good-enough tests that use the filesystem and delays (although these are sensitive to kernel startup time). Once we have dependency ordering, it should simplify our tests but we might wish to implement a helper such as a socket server that enforces resource counting (e.g. ensure this lock counter never exceeds 1, or ensure this lock counter reaches 2). |
|
I've run out of time to debug this further today, so I'd welcome anyone to take it over the line. I'm not immediately sure why the tests pass locally but fail on CI. |

Following discussions on #2413 and #1831, this PR introduces
--execute-concurrency <n>only.@agoose77 I tested this locally and it seems to be working. I did not implement an
if (execute) {conditional inprocess::site, which as @fwkoch noted is not really needed. The only subtlety is the difference between the “effective” and “apparent” number of pages to execute, but users are free to set as low as 1 if desired, noted in the docs.I hope I got the changeset right 👀