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 for autosaving PV values #162

Open
jsouter opened this issue Jun 27, 2024 · 10 comments
Open

Support for autosaving PV values #162

jsouter opened this issue Jun 27, 2024 · 10 comments

Comments

@jsouter
Copy link

jsouter commented Jun 27, 2024

I have been working on an IOC to track the placement of samples on a carousel. It would be convenient if the readback values for the sample names at various positions would persist after an IOC restart in case of a power off event (or anything else prompting an IOC restart) so that they don't have to be manually scanned/written back in. I could rewrite as a normal C++ asyn IOC or implement my own autosave by writing to the filesystem but more official autosave support would be helpful.

@olliesilvester
Copy link

MX would also find this useful. We have a use-case where we'd like to have a baton between GDA and Bluesky software, which is ran on a Python IOC. An autosave would be needed so it remembers who is in control after crashing / needing a restart.

@coretl
Copy link
Contributor

coretl commented Jul 1, 2024

@jsouter I think my preferred approach would be a pure python interface like I07's. Can you think of a way to make it generic so it could be put into pythonSoftIOC?

@jsouter
Copy link
Author

jsouter commented Jul 1, 2024

I'll have a look at what's being done on i07 and see what I can come up with

@jsouter
Copy link
Author

jsouter commented Jul 2, 2024

Drafting this here: https://github.com/jsouter/pythonSoftIOC/tree/autosave
Currently you have to instantiate the Autosave class and pass to it a list of PVs you want to save, trying to inspect if there's a good way to use some builder magic to get a list of the records so that we could use .req files instead and look for PVs globally by name, though maybe explicitly passing the PV objects (RecordWrappers, technically) to Autosave is preferable. Right now the onus on the IOC developer to periodically call save in their main dispatcher loop, though it could be reworked so that there's always an autosave loop running in the background that periodically calls save if the save_period has elapsed and any of the PVs have changed.

@Araneidae
Copy link
Collaborator

I suggest two things:

  • Use an extra builder argument (maybe autosave=True) to automatically mark PVs for autosaving
  • Run a background thread to periodically check for changes

It might be worth having a look at how epics_device does things. However, this is written in C and so may be a less accessible reference.

@AlexanderWells-diamond
Copy link
Collaborator

I echo Michael's advice of using another flag during the build process to mark PVs for autosaving. Seems much cleaner than trying to maintain a separate list of PVs to be saved.

Although with the mention of .req files, this sounds like you have an alternative idea of how the interface should work. Is that file the one that is used by the EPICS autosave feature?

P.S. You can inspect the list of created records by calling softioc.device_core.LookupRecordList()

@jsouter
Copy link
Author

jsouter commented Jul 2, 2024

Cheers both, just noticed builder.LookupRecord() which should solve that problem. I think the background thread/builder argument approach makes sense so I will have a go at that.
.req files are what the regular autosave module uses, just acts as a list of PVs that should be saved/loaded, I have no real preference for doing it this way just wondered if people thought it better to pass it in as configuration/make it look more like the C/C++ version.

@jsouter
Copy link
Author

jsouter commented Jul 3, 2024

Okay, have a version of that here https://github.com/jsouter/pythonSoftIOC/tree/autosave, the autosave thread gets kicked off during the __init__for CothreadDispatcher/AsyncioDispatcher. I believe this works as expected but I will need to do some work to figure out where the thread should be started and how to handle its shutdown.

The directory must be set by calling softioc.autosave.configure as below

from softioc import softioc, builder
from softioc.asyncio_dispatcher import AsyncioDispatcher
import asyncio
from softioc import autosave
import time

DEVICE_NAME = "MY-SOFT-IOC-01"


builder.SetDeviceName(DEVICE_NAME)
autosave.configure(directory=f"/tmp/data/{DEVICE_NAME}", save_period = 5)
saved_ao = builder.aOut('SAVEME', autosave=True)
unsaved_ao = builder.aOut('DONTSAVEME', autosave=False)

async def main():
    i = saved_ao.get()
    j = unsaved_ao.get()
    while True:
        i += 1
        j += 1
        await asyncio.sleep(1)
        saved_ao.set(i)
        unsaved_ao.set(j)
        print(saved_ao.get(), unsaved_ao.get())

builder.LoadDatabase()
dispatcher = AsyncioDispatcher()
softioc.iocInit(dispatcher(main))
softioc.interactive_ioc(globals())

The autosave directory could be passed in with argparse or read from a config file

@AlexanderWells-diamond
Copy link
Collaborator

That looks like a good initial go at an implementations, it's probably time to open a PR so we can give more precise feedback.

Where the autosave directory comes from is immaterial to pythonSoftIoc itself, it'd be dependant on how exactly the users want to load that data.

@Araneidae
Copy link
Collaborator

Rather than walking the complete list of PVs on every autosave cycle you could instead maintain a list of PVs that are marked with the autosave flag and add PVs to this list (by calling into the autosave module) when you see the autosave flag set.

On that note, you should be able to push the resulting if kargs.pop('autosave', False): autosave.add_pv(self) call up to the common ProcessDeviceSupportCore class rather than repeating it for each subclass. (I wouldn't push it any higher up the hierearchy, though!)

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

No branches or pull requests

5 participants