Skip to content
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

Support optionally restarting interactive processes when input files change #13178

Merged

Conversation

stuhood
Copy link
Sponsor Member

@stuhood stuhood commented Oct 8, 2021

Adds pex_binary(.., restartable=True) and repl --restartable to optionally allow user processes to be restarted when files change. See run_integration_test.py for an example.

InteractiveProcess is used for any process that needs to run in the foreground, including those for run, and repl. To support restarting those processes, we make invoking an InteractiveProcess async, which allows it to (optionally) be restarted when files change.

To make InteractiveProcess async, we convert it into a rust-side Intrinsic, and introduce a new Effect awaitable type, which is used in place of Get when a type is SideEffecting. This also prepares the other SideEffecting param types to be converted to Effects as well (in order to accomplish #10542).

Fixes #9462.

@stuhood stuhood force-pushed the stuhood/sideeffect-based-restartability branch 5 times, most recently from c847d4c to 0b12c42 Compare October 10, 2021 23:12
@stuhood stuhood changed the title Rules are restartable unless they have had sideeffects Support optionally restarting interactive processes when input files change Oct 10, 2021
@stuhood stuhood marked this pull request as ready for review October 10, 2021 23:31
@stuhood
Copy link
Sponsor Member Author

stuhood commented Oct 10, 2021

This is atop #13199 currently, but is reviewable.

The commits are somewhat useful to review independently, but the second and third overlap one another quite a bit.

@stuhood stuhood force-pushed the stuhood/sideeffect-based-restartability branch 2 times, most recently from 52a9915 to f5c289b Compare October 11, 2021 04:16
)
if signature is not None:
product_str, subject_str, effect = signature
get = AwaitableConstraints(
Copy link
Sponsor Contributor

Choose a reason for hiding this comment

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

Are get/gets still appropriate var names here? (and in validate_requirements()?) One might also be an effect, no?

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

There is going to be a long tail of updates required, for sure. I'm not really sure what the best abstract name for the new concept is (used Awaitable in selectors, but mostly because that was what it was used for in that file). But I'll change the local variable names nearby Awaitable* at least.

Copy link
Member

@kaos kaos left a comment

Choose a reason for hiding this comment

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

Cool stuff.
Think there's only a few outstanding nits and bits for error feedback, could be done as follow up too..

src/python/pants/engine/internals/selectors.py Outdated Show resolved Hide resolved
src/python/pants/engine/process.py Outdated Show resolved Hide resolved
src/python/pants/engine/rules.py Show resolved Hide resolved
src/python/pants/core/goals/run.py Outdated Show resolved Hide resolved
Copy link
Contributor

@Eric-Arellano Eric-Arellano left a comment

Choose a reason for hiding this comment

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

🤘

src/python/pants/engine/internals/selectors.py Outdated Show resolved Hide resolved
src/python/pants/core/goals/run.py Outdated Show resolved Hide resolved
src/python/pants/core/goals/run.py Outdated Show resolved Hide resolved


@ensure_daemon
def test_run_then_edit(use_pantsd: bool) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

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

Sweet!

@@ -490,7 +491,7 @@ async def run_tests(
OpenFiles, OpenFilesRequest(coverage_report_files, error_if_open_not_found=False)
)
for process in open_files.processes:
interactive_runner.run(process)
_ = await Effect(InteractiveProcessResult, InteractiveProcess, process)
Copy link
Contributor

Choose a reason for hiding this comment

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

No need for _ =

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

When discarding something, I like to make it clear that it's intentional.

[ci skip-rust]

[ci skip-build-wheels]
… support configuring whether to restart.

[ci skip-build-wheels]

# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]
[ci skip-build-wheels]
# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
@stuhood stuhood force-pushed the stuhood/sideeffect-based-restartability branch from f5c289b to 1e82cda Compare October 11, 2021 15:58
@stuhood stuhood enabled auto-merge (squash) October 11, 2021 15:58
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
Comment on lines +73 to +74
"If your application can safely be restarted while it is running, you can pass "
"`restartable=True` on your binary target (for supported types), and the `run` goal "
Copy link
Contributor

Choose a reason for hiding this comment

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

Imo pass => CLI arg, set => change a BUILD file.

Suggested change
"If your application can safely be restarted while it is running, you can pass "
"`restartable=True` on your binary target (for supported types), and the `run` goal "
"If your application can safely be restarted while it is running, you can set "
"`restartable=True` on your binary target (for supported types), and the `run` goal "

"If your application can safely be restarted while it is running, you can pass "
"`restartable=True` on your binary target (for supported types), and the `run` goal "
"will automatically restart them as all relevant files change. This can be particularly "
"useful for server applications."
Copy link
Contributor

Choose a reason for hiding this comment

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

like Django and Flask.

stuhood added a commit that referenced this pull request Oct 28, 2021
…t spurious restarts. (#13385)

Unlike `run_rule_with_mocks`, `RuleRunner.run_goal_rule` does actually run a `Goal` via the engine, and is thus subject to being restarted when its inputs have changed (see #13178). Consequently, the `Console` and `Workspace` types _do_ need to track side-effects in that context, in order to prevent the `@rule` from being restarted after its first side-effect.

This was exhibiting as test flakiness for a goal that re-writes files in the workspace (see #13383), because after writing the updated lockfile to disk, the `@rule` has changed its own inputs and is subject to restart: if the restart arrived before any `Console` output was written, the second attempt to run the rule would not find anything to do, and would thus not render any `Console` output.

Fixes #13383.

[ci skip-rust]
[ci skip-build-wheels]
f"A `@rule` that was not a @goal_rule ({func_id}) has a `SideEffecting` parameter: {ty}"
)
if not cacheable:
return
Copy link
Member

Choose a reason for hiding this comment

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

Just realized now, that this early return cancels all the Effect checks further down for @goal_rules. cc @stuhood

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

Thanks! #14069.

stuhood added a commit that referenced this pull request Jan 4, 2022
#13178 added additional validation of use of `Effect`s in `@goal_rules` but it was accidentally unreachable. 

[ci skip-rust]
[ci skip-build-wheels]
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.

Allow for reloading of python code changes in a repl or development session
4 participants