Skip to content

Support for autosaving PV values #162

Closed

Description

@jsouter

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.

Activity

  1. olliesilvester commented on Jun 27, 2024

    @olliesilvester

    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.

  2. coretl commented on Jul 1, 2024

    @coretl
    Contributor

    @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?

  3. jsouter commented on Jul 1, 2024

    @jsouter
    ContributorAuthor

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

  4. jsouter commented on Jul 2, 2024

    @jsouter
    ContributorAuthor

    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.

  5. Araneidae commented on Jul 2, 2024

    @Araneidae
    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.

  6. AlexanderWells-diamond commented on Jul 2, 2024

    @AlexanderWells-diamond
    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()

  7. jsouter commented on Jul 2, 2024

    @jsouter
    ContributorAuthor

    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.

  8. jsouter commented on Jul 3, 2024

    @jsouter
    ContributorAuthor

    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

  9. AlexanderWells-diamond commented on Jul 3, 2024

    @AlexanderWells-diamond
    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.

  10. Araneidae commented on Jul 3, 2024

    @Araneidae
    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!)

  11. AlexanderWells-diamond commented on Sep 13, 2024

    @AlexanderWells-diamond
    Collaborator

    Completed as of #163

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions