即使这个问题有点过时,我还是想发布一个答案,因为 Retry 状态已添加到 transitions 在发布 0.9 中。
Retry 本身只会计算重新进入状态的频率,这意味着当转换源和目标相等时计数器将增加,否则将重置。它完全是被动的,需要另一种方法来触发事件。除了Retry 之外,通常使用Timeout 状态扩展来实现此目的。在下面的示例中,状态机装饰有Retry 和Timeout 状态扩展,允许使用几个关键字来定义状态:
-
timeout - 进入状态后触发超时前的时间(以秒为单位)
-
on_timeout- 触发 timeout 时调用的回调
-
retries - 重新进入状态时调用失败回调之前的重试次数
-
on_failure - 当重入计数器到达 retries 时调用的回调
该示例将重新输入pinging,除非随机生成的介于 0 和 1 之间的数字大于 0.8。这可以解释为一个服务器,它粗略地只回答每五个请求。当您执行该示例时,达到“已初始化”所需的重试可能会有所不同,甚至在达到retries 时会失败。
from transitions import Machine
from transitions.extensions.states import add_state_features, Retry, Timeout
import random
import time
# create a custom machine with state extension features and also
# add enter callbacks for the states 'pinging', 'initialized' and 'init_failed'
@add_state_features(Retry, Timeout)
class RetryMachine(Machine):
def on_enter_pinging(self):
print("pinging server...")
if random.random() > 0.8:
self.to_initialized()
def on_enter_initialized(self):
print("server answered")
def on_enter_init_failed(self):
print("server did not answer!")
states = ["init",
{"name": "pinging",
"timeout": 0.5, # after 0.5s we assume the "server" wont answer
"on_timeout": "to_pinging", # when timeout enter 'pinging' again
"retries": 3, # three pinging attempts will be conducted
"on_failure": "to_init_failed"},
"initialized",
"init_failed"]
# we don't pass a model to the machine which will result in the machine
# itself acting as a model; if we add another model, the 'on_enter_<state>'
# methods must be defined on the model and not machine
m = RetryMachine(states=states, initial="init")
assert m.is_init()
m.to_pinging()
while m.is_pinging():
time.sleep(0.2)