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

refactor(api, robot-server): Refactor ProtocolRunner per protocol type #12343

Merged
merged 36 commits into from
Apr 17, 2023

Conversation

TamarZanzouri
Copy link
Contributor

@TamarZanzouri TamarZanzouri commented Mar 22, 2023

Overview

Closes RSS-200.
create an abstract interface for ProtocolRunner and implement per JsonRunner PythonAndLegacyRunner and LiveRunner.

Also fixes a bug that was causing live http runs to finish executing the run after the first command (RSS-214).

Test Plan

  • Upload python 2.14, json v6, legacy python protocols and make sure you're able to analyze protocols, run LPC and run protocols. Check that:
    • all runs are created correctly
    • can be started, paused and stopped
    • run results are correct
  • (Optional)Test a LiveRunner: Start an empty run and post protocol-intent commands. Make sure all commands are run successfully. Also test pausing and stopping the protocol.

Changelog

  • Refactor ProtocolRunner to be an abstract and implement per JsonRunner PythonAndLegacyRunner and LiveRunner.
  • create_simulating_runner is now constructed per file type.
  • Change ProtocolAnalyzer to create on the fly the simulating runner instead of injecting it.
  • Changed tests that were using an empty run.

Review requests

  • I (Sanniti) have tested the changes on the dev server but it's important to test on a real robot (ot2/ot3 either works) since run flow control actions can't be tested on the dev server.
  • We have talked about how having a runner that can allow execution of batch commands could be useful for future features. I agree that it would be useful but the way the engine & run is architected currently, it would need a more detailed change to the architecture (more importantly, careful testing) than is strictly necessary for run split. So I have not attempted to do that in this PR. We will be able to make that change in the future when the feature is on the roadmap.
  • Currently we are setting run_started_at (also in the run response) when there is a play action. with this change we will no longer set this value for setup commands/post commands. this is the only real noticeable change -> might want to check with UI folks. they should use createdAt instead for this case.

Risk assessment

Medium-high. need to make sure nothing is effected from the refactor for all protocol types and for posting commands/runs with no protocol.

@TamarZanzouri TamarZanzouri requested review from a team as code owners March 22, 2023 19:46
protocol_source: Optional[ProtocolSource] = None,
) -> ProtocolRunResult:
"""Run a given protocol to completion."""
# TODO(mc, 2022-01-11): move load to runner creation, remove from `run`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

can totally do this for this pr

@@ -37,3 +51,13 @@ stages:
- id: 'RunActionNotAllowed'
title: 'Run Action Not Allowed'
detail: 'Cannot pause a run that is not running.'

Copy link
Contributor Author

@TamarZanzouri TamarZanzouri Mar 23, 2023

Choose a reason for hiding this comment

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

investigate why this is hanging without the stop

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is hanging on edge too

@codecov
Copy link

codecov bot commented Mar 23, 2023

Codecov Report

Merging #12343 (5789c41) into edge (bc70828) will decrease coverage by 0.11%.
The diff coverage is 75.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##             edge   #12343      +/-   ##
==========================================
- Coverage   73.81%   73.70%   -0.11%     
==========================================
  Files        2228     2220       -8     
  Lines       61587    61316     -271     
  Branches     6382     6374       -8     
==========================================
- Hits        45461    45194     -267     
+ Misses      14637    14635       -2     
+ Partials     1489     1487       -2     
Flag Coverage Δ
notify-server 89.13% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
api/src/opentrons/protocol_runner/__init__.py 100.00% <ø> (ø)
...ntrons/protocol_runner/create_simulating_runner.py 84.61% <ø> (-2.89%) ⬇️
...i/src/opentrons/protocol_runner/legacy_wrappers.py 100.00% <ø> (ø)
...obot-server/robot_server/protocols/dependencies.py 100.00% <ø> (ø)
...server/robot_server/protocols/protocol_analyzer.py 100.00% <ø> (ø)
robot-server/robot_server/runs/engine_store.py 96.00% <ø> (-0.08%) ⬇️
g-code-testing/g_code_parsing/g_code_engine.py 81.31% <50.00%> (ø)
...i/src/opentrons/protocol_runner/protocol_runner.py 100.00% <100.00%> (ø)

... and 50 files with indirect coverage changes

@TamarZanzouri TamarZanzouri added the robot-svcs Falls under the purview of the Robot Services squad (formerly CPX, Core Platform Experience). label Mar 23, 2023
False, True
)

assert legacy_subject.was_started() is False
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is wrong. need to fix this test to test real cases

Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

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

Looking great so far!

api/src/opentrons/protocol_runner/protocol_runner.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_runner/protocol_runner.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_runner/protocol_runner.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_runner/protocol_runner.py Outdated Show resolved Hide resolved
api/src/opentrons/protocol_runner/protocol_runner.py Outdated Show resolved Hide resolved
@TamarZanzouri
Copy link
Contributor Author

Tested on an OT-2 with json, python, legacy protocols. tested with live protocol commands. works as expected.

"""Create a ProtocolRunner wired to a simulating HardwareControlAPI.
async def create_simulating_runner(
robot_type: RobotType, protocol_config: ProtocolConfig
) -> AbstractRunner:

This comment was marked as resolved.

@@ -27,43 +31,75 @@
)


class ProtocolRunResult(NamedTuple):
class RunnerRunResult(NamedTuple):

This comment was marked as outdated.

"""An interface to manage and control a protocol run.

The ProtocolRunner is primarily responsible for feeding a ProtocolEngine
The AbstractRunner is primarily responsible for feeding a ProtocolEngine
with commands and control signals. These commands and signals are
generated by protocol files, hardware signals, or externally via

This comment was marked as outdated.

# TODO(mc, 2022-01-11): this class has become bloated. Split into an abstract
# interfaces and several concrete implementations per protocol type
class ProtocolRunner:
class AbstractRunner(ABC):

This comment was marked as outdated.

Comment on lines 254 to 267
def play(self) -> None: # noqa: D102
self._protocol_engine.play()

def pause(self) -> None: # noqa: D102
self._protocol_engine.pause()

async def stop(self) -> None: # noqa: D102
if self.was_started():
await self._protocol_engine.stop()
else:
await self._protocol_engine.finish(
drop_tips_and_home=False,
set_run_status=False,
)
Copy link
Member

Choose a reason for hiding this comment

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

I think we can implement these in the abstract itself.

self._protocol_engine.add_plugin(
LegacyContextPlugin(broker=broker, equipment_broker=equipment_broker)
async def load(self, protocol_source: ProtocolSource) -> None: # noqa: D102
raise NotImplementedError(
Copy link
Member

Choose a reason for hiding this comment

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

Raise a more appropriate error

async def create_simulating_runner(robot_type: RobotType) -> ProtocolRunner:
"""Create a ProtocolRunner wired to a simulating HardwareControlAPI.
async def create_simulating_runner(
robot_type: RobotType, protocol_config: ProtocolConfig
Copy link
Member

Choose a reason for hiding this comment

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

See if accepting a protocol_type makes more sense here.

Copy link
Member

Choose a reason for hiding this comment

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

Adding a TODO to address later.

@sanni-t sanni-t changed the title refactor(api, robot-server): Refactor ProtocolRunner per protocol type and add MaintenanceRunner refactor(api, robot-server): Refactor ProtocolRunner per protocol type Apr 5, 2023
Copy link
Contributor

@b-cooper b-cooper left a comment

Choose a reason for hiding this comment

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

Tested via App branch build, successfully analyzed python and json protocols. ✅

Copy link
Member

@sanni-t sanni-t left a comment

Choose a reason for hiding this comment

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

Comments from live review.

await self._protocol_engine.stop()
else:
await self._protocol_engine.finish(
drop_tips_and_home=False,
Copy link
Member

Choose a reason for hiding this comment

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

Investigate if this should be actually true.

Copy link
Member

Choose a reason for hiding this comment

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

Our current code in edge does tip drop only after a clean protocol run finish and not in runner.stop (run cancellation) so this keeps that behavior as is and is correct.

from opentrons.protocol_runner import create_simulating_runner
from opentrons.protocols.api_support.types import APIVersion


# TODO (tz, 6-17-22): API version 3.x in-development.
Copy link
Member

Choose a reason for hiding this comment

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

Check what's going on here. Why's this xfailing?

@@ -1,6 +1,6 @@
"""Smoke tests for the ProtocolRunner and ProtocolEngine classes.
"""Smoke tests for the AbstractRunner and ProtocolEngine classes.

This comment was marked as resolved.

Copy link
Member

Choose a reason for hiding this comment

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

There's an integration test for LiveRunner which covers the requirement.



@pytest.fixture
def legacy_subject(
Copy link
Member

Choose a reason for hiding this comment

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

Rename to python_runner_subject?

robot-server/robot_server/protocols/protocol_analyzer.py Outdated Show resolved Hide resolved
robot-server/robot_server/runs/engine_store.py Outdated Show resolved Hide resolved
await runner.load(protocol.source)
else: # Why does linter not like `else:`..?
Copy link
Member

Choose a reason for hiding this comment

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

I think this is outdated comment.

Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

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

This looks like a big improvement, thanks @TamarZanzouri and @sanni-t. It's nice that JSON runs don't have to care about dependencies for Python runs anymore, and vice-versa. Looks good to me to merge once comments are resolved.

Here are a bunch of little things, sorry for the spam!

@@ -96,6 +96,8 @@ def read(
)


# TODO (spp, 2023-04-05): Remove 'legacy' wording since this is the context we are using
Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

@TamarZanzouri
Copy link
Contributor Author

Totally agree with the changes added. Makes sense to move common implementations to the abstract. Thank you for fixing this @sanni-t

Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

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

Woohoo! -=≡ヘ(*・ω・)ノ

Copy link
Contributor

@jbleon95 jbleon95 left a comment

Choose a reason for hiding this comment

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

Looks good!

@sanni-t sanni-t merged commit 214f225 into edge Apr 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
robot-svcs Falls under the purview of the Robot Services squad (formerly CPX, Core Platform Experience).
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants