Comments (5)
Hi @UweSauter, I've wrote a small example of how this can be done using a custom model.
Please note that I've implemented this as issue358_persistence.md example file, so the tests actually run locally (the getfixture
is a fixture from pytest to get a temporary file)
Issue 358
A StateMachine
that has its current state persisted automatically using a custom model.
Given a generic API from a model with a state
property: GenericStorageModel
:
>>> from abc import ABC
>>> from abc import abstractmethod
>>> class GenericStorageModel(ABC):
... """Abstract Base Class for persistent models.
...
... Sub classes should implement concrete strategies for:
...
... - `_read_state`: Read the state from the concrete persistent layer.
... - `_write_state`: Write the state from the concrete persistent layer.
... """
... def __init__(self,):
... self._state = None
...
... def __repr__(self):
... return f"{type(self).__name__}(state={self.state})"
...
... @property
... def state(self):
... if self._state is None:
... self._state = self._read_state()
... return self._state
...
... @state.setter
... def state(self, value):
... self._state = value
... self._write_state(value)
...
... @abstractmethod
... def _read_state(self):
... raise NotImplementedError()
...
... @abstractmethod
... def _write_state(self, value):
... raise NotImplementedError()
You can write many concrete implementations of a storage strategy, persisting to YAML, JSON,
database, etc. For this example to be complete, I have for you here a reference on how to write into a file.
>>> class FileStorageModel(GenericStorageModel):
... """A concrete implementation of a storage strategy for a Model"""
... def __init__(self, file_path):
... super().__init__()
... self.file_path = file_path
...
... def _read_state(self):
... if not self.file_path.exists():
... return
...
... with self.file_path.open('r') as f:
... return f.read().strip()
...
... def _write_state(self, value):
... with self.file_path.open('w+') as f:
... return f.write(value)
You can use this FileStorageModel
or any other persistent strategy that you like as a domain
model.
So, given this simple SM:
>>> from statemachine import StateMachine, State
>>> class ResourceManagement(StateMachine):
... power_off = State(initial=True)
... power_on = State()
...
... turn_on = power_off.to(power_on)
We can create instances:
>>> tmp_path = getfixture('tmp_path')
>>> state_path = tmp_path / 'resource_state.txt'
>>> model = FileStorageModel(file_path=state_path)
>>> sm = ResourceManagement(model=model)
>>> sm.current_state.id
'power_off'
>>> sm.send("turn_on")
>>> sm.current_state.id
'power_on'
>>> del sm
>>> del model
Restore the previous state from disk:
>>> model = FileStorageModel(file_path=state_path)
>>> sm = ResourceManagement(model=model)
>>> sm.current_state.id
'power_on'
from python-statemachine.
Wow, thank you. I didn't expect to get such a detailed example.
I'll need to start coding to see if this fits my requirements.
Thanks again.
from python-statemachine.
Hi @UweSauter , how are you?
You can inspect the current state using the current_state
property of the state machine, or in this case, you can also use the low level current_state_value
property, that can be assigned to any valid state value completely bypassing all the hooks and validation. This way you can read/write the current state.
But there's no built-in function for serialization, and you can use plain standard Python to read current_state_value
and write to disk.
As suggestion, you can implement a generic on_enter_state
hook that does this at every state change.
Let me know if you need any help on this, if so, consider adding more concrete info about how is your use case and how do you plan to store the state.
Best regards!
from python-statemachine.
Hi Fernando,
thanks for the explanation.
So, I'm at the very early phase of making a concept for a compute resource management software. The software should track the various states the compute servers can have and transition between these states upon internal and external triggers.
An external trigger would be that the administrator wants to turn on power and the management software then calls ipmitool power on
for that particular server (and transition the state from power_off
to power_on
).
An internal trigger would be the repeating health checks that are executed by the management software and upon success (or failure) of the check, the state is changed accordingly.
As suggestion, you can implement a generic on_enter_state hook that does this at every state change.
This way it would be able to store the state on disk, be it as JSON or YAML or in a database.
What I don't get is: how could I restore the states from disk when the management software is started (e.g. after a reboot)?
Would it also be possible to pickle.dumps()
the state machine instance and restore that state machine later with pickle.loads()
?
Regards,
Uwe
from python-statemachine.
@UweSauter I will close the issue for now, feel free to comment or open an issue if something is missing, ok?
Best regards!
from python-statemachine.
Related Issues (20)
- Event keyword arguments are silently overwritten when particular keyword argument names are used HOT 4
- Finalize action after transition success or failure. HOT 1
- feature request: async callbacks HOT 3
- Incompatible with spy wrapper from pytest-mock HOT 3
- Add automation (GH action) to publish a new version on pypi HOT 1
- Simple question HOT 10
- Generate the code from PlantUML diagrams HOT 2
- Type annotations missing for `initial_state` and `final_states`; leading to linting errors with Pylint/Pyright HOT 3
- Expensive instantiation of StateMachine HOT 3
- AttributeError: object has no attribute 'model' HOT 3
- Enable Multithreading HOT 2
- [Feature request] State machine based workflow for database storage on entity state tracking HOT 1
- Action callback gets called twice when mixing definition methods HOT 1
- Check that all state transitions can reach a final state. HOT 6
- Execute a state machine from another state machine HOT 1
- Guards and conditions passed as strings really necessary? HOT 6
- ROS2, state transition not possible HOT 2
- Send a state machine over MQTT / serializing-deserializing a SM HOT 6
- Question: How can I use cond functions to gatekeep, but not fail? HOT 5
- Failed to generate a graphic image HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from python-statemachine.