-
Notifications
You must be signed in to change notification settings - Fork 6
Add Blocking Flag to Command PVs #141
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
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #141 +/- ##
==========================================
+ Coverage 90.59% 90.63% +0.03%
==========================================
Files 41 41
Lines 1935 1943 +8
==========================================
+ Hits 1753 1761 +8
Misses 182 182 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Hmmm this may require some thought on how to standardise. PVAIn pva I set the command widget to true while the command is running, then false after it has finished. FastCS/src/fastcs/transport/epics/pva/_pv_handlers.py Lines 53 to 90 in 1cce8ea
This means that I don't mind changing this to do blocking until the command is complete, but if so we should agree on this as a standard. Unless I'm mistaken, the pva analogue of the above would be to # Flip to true after the command ends
alarm_states = await self._run_command()
pv.post({"value": True, **p4p_timestamp_now(), **alarm_states})
op.done()and remove the |
|
I could imagine you might want either... so it probably needs to be a flag on |
I was thinking the same, though we probably want it to be a kwarg of type: class CommandMode(enum.Enum):
#: Command value becomes `True` in the transport only
#: once the command starts, becomes `False` after it
#: finishes.
CONTINUE_AFTER_START = "CONTINUE_ONCE_STARTED"
#: Command value becomes `True` in the transport only after
#: the command has finished. Becomes `False` immediately after.
CONTINUE_AFTER_FINISH = "CONTINUE_AFTER_FINISH" |
|
I think |
|
Yea that's much nicer. class CommandMode(enum.Enum):
#: Command value becomes `True` in the transport once
#: the command starts, becomes `False` after it finishes.
HIGH_AFTER_START = "HIGH_AFTER_START"
#: Command value becomes `True` in the transport only after
#: the command has finished. Becomes `False` immediately after.
HIGH_AFTER_FINISH = "HIGH_AFTER_FINISH" |
|
@shihab-dls is there an issue to do with arming eiger that this would fix? |
This should unblock #551, where the Eiger's |
|
@coretl @DominicOram do you have any thoughts on the behaviour we might want here? |
|
I've just pushed some rough commits outlining the behaviour we're describing (to my understanding). @GDYendell and @evalott100 did I follow correctly? Happy to revert the changes if it's decided |
|
I think we always want So the order should be:
|
|
So we don't need the option @shihab-dls, it should always do Action(blocking=True) and the pva version should be updated to match @coretl's description above. |
This would be equivalent to what we have in the PVA transport right now, so long as we swap the done around to be after everything in the CommandPvHandler: # Flip to true once command task starts
pv.post({"value": True, **p4p_timestamp_now(), **p4p_alarm_states()})
alarm_states = await self._run_command()
pv.post({"value": False, **p4p_timestamp_now(), **alarm_states})
op.done()
else:
raise RuntimeError("Commands should only take the value `True`.")This causes the behavior we expect for commands: async def do_nothing():
print("STARTED COMMAND")
await asyncio.sleep(10)
print("ENDED COMMAND")
class ControllerLongNames(Controller):
command_short_name = Command(do_nothing)
[:(] pvput -w 5 MEH:CommandShortName true
Old : 2025-03-21 14:24:35.584 false
Put timeout
SuggestionFor equivalence to the p4p backend we change from using a
|
I don't think this is what you found, is it @shihab-dls ? |
I've been testing this out; it seems it is true that the record value is set immediately, which means that: @command()
async def comm(self):
print("Started command")
await asyncio.sleep(5)
print("Finished command")with $ pvput -w 1 blah:Comm 1
Old : 2025-03-24 10:45:27.418 (0)
New : 2025-03-24 10:48:52.454 (1) where the put does not timeout. Similarly, a pvget results in: $ pvget -w 1 blah:Comm
blah:Comm 2025-03-24 10:50:21.889 (1)where the new record value is immediately available. However, the operation completion is only triggered after the callback completes, which mean monitors are updated after the callback: $ pvput -w 1 blah:Comm 1
Old : 2025-03-24 11:03:32.414 (0)
New : 2025-03-24 11:03:52.857 (1)$ pvmonitor blah:Comm
blah:Comm 2025-03-24 11:03:32.414 (0) where the monitor does not update until 5 seconds later: $ pvmonitor blah:Comm
blah:Comm 2025-03-24 11:03:32.414 (0)
blah:Comm 2025-03-24 11:03:57.858 (1)If you were to
for example: followed by: which I believe is why @evvaaaa wants us using
It seems, however, that a put with callback waits for server processing to be complete, which means that it correctly waits for the TLDRSetting
This means a However, the records
Which means that doing a put with callback will correctly wait for callback completion before returning. |
I don't have much to contribute to the details of this but I agree with @coretl that the callback should only return on the process being completed. Otherwise we have no reliable way to tell something has completed from the client side. If a client chooses not to wait for that callback then that's up to individual clients |
|
These final commits should now have this PR doing the following:
which should have our put callbacks, regardless of backend, return after a bound method has completed. |
Note that is for CA via the pythonSoftIOC transport, and PVA via the p4p transport. PVA via the pythonSoftIOC transport currently doesn't wait for completion due to epics-base/pvxs#105. This is not a blocker for FastCS (as we will use PVA via the p4p transport, so will probably turn it off in pythonSoftIOC via DiamondLightSource/pythonSoftIOC#185), but we will need this later for areaDetector IOCs when we go full PVA on beamlines. |
GDYendell
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 good now. I suggest we have a brief discussion in the stand up to make sure we are in agreement and then merge.
|
We should make sure that we match the behaviour of the IOCs, so if we |
Looks like with $ time pvput -r "record[block=true]" -w 10 blah:Comm 1
Old : <undefined> INVALID DRIVER UDF (0)
New : 2025-03-26 12:29:02.427 (1)
real 0m5.009swhere we timeout if $ time pvput -r "record[block=true]" -w 4 blah:Comm 1
Old : 2025-03-26 12:32:44.686 (0)
Put timeout
real 0m4.009sbut the value is changed when we check afterwards: $ pvget blah:Comm
blah:Comm 2025-03-26 12:33:02.479 (1)Blocking Behaviour Post Merge:
Is this the behaviour that was agreed upon, @coretl and @GDYendell? Where P4P waits for callback completion regardless of additional flags (where -w is sort of required to ensure no timeout)? |
|
After pythonSoftIOC #186, behaviour will be:
Where Current PR behaviour:
Which should better match epics-base/pvxs#105 (comment) |
This reverts commit 862ea4c.
|
PR should be ready for re-review now. Note: |
When we put to a command PV, the put returns immediately, not waiting for the bound callback to complete. Adding the
blocking=Trueflag sets the PVsPACTfield high until the bound callback sets the PVs status to completed. This should allow an ophyd-asyncSignalXto be properly awaited.I'm not sure if this behaviour should be set like this, however; is it always the case we'd want to wait for a callback when processing a command PV?