In this example I use a event to signal when to stop processing. The event is passed down the nested chain to the bottom processes. When the event is triggered, the bottom process stops processing and returns a status flag to the calling process which uses to status to decide how to proceed, also stopping.
"""
Sim showing how to interupt a nested chain of processes
using a event to signal when to stop processing
This example is perhaps the most gracefull
In this example, event is created and passed down to the bottom
process. When the event is triggered the bottom process stops
process and returns a event value 'Stopped', so the calling process
will know the child stopped early. No itterupts are used.
Note that the bottom process is the first to be interupted
Programmer: Michael R. Gibbs
"""
import simpy
def bottom_process(env, stop_event):
"""
end process in nested chain of processes
returns a end status of Success, Stopped, Interrupted
"""
print(f'{env.now} starting bottom process')
try:
# do something that takes a bit of sim time
# also yield to the stop event for early end of processing
event_map = yield env.any_of([env.timeout(10), stop_event])
if stop_event in event_map:
# the stop event fired, do not finish processing
print(f'{env.now} bottom process has been stopped')
return 'Stopped'
print(f'{env.now} bottom process finished')
return 'Success'
except simpy.Interrupt as err:
print(f'{env.now} bottom process interupted')
return 'Interrupted'
def mid_process(env, stop_event):
"""
Middle process in a nested chain of processes
return end status of Succes, Interrupted, or Stopped
"""
print(f'{env.now} starting middle process')
# start next nested process, pass down the bomb
bottom_event = env.process(bottom_process(env, stop_event))
try:
# wait for child to finish
status = yield bottom_event
# use the status to check if processing was stopped early
if status == 'Stopped':
print(f'{env.now} middle process has been stopped')
return 'Stopped'
print(f'{env.now} mid process finished')
return 'Success'
except simpy.Interrupt as err:
print(f'{env.now} mid process interupted')
return 'Interrupted'
def top_process(env, stop_event):
"""
The top starting process in a chain of nested processes
returns a status of Success, Interrupted, or Stopped
"""
print(f'{env.now} starting top process')
# start the next nested process in the chain
# pass down the bomb
mid_event = env.process(mid_process(env, stop_event))
try:
status = yield mid_event
# check the status to see if processing was stopped early
if status == 'Stopped':
print(f'{env.now} Top process has been stopped')
return 'Stopped'
print(f'{env.now} top process finished')
return 'Success'
except simpy.Interrupt:
print(f'{env.now} top process interupted')
return 'Interrupted'
def main_process(env):
"""
Main process that starts a nested chain of processes,
passing down a stop event
"""
print(f'{env.now} starting main')
# create a event to signal when to stop
stop_event = env.event()
env.process(top_process(env, stop_event))
yield env.timeout(3)
# trigger event to stop processing
stop_event.succeed()
print(f'{env.now} main has finish')
# boot up the whole mess
env = simpy.Environment()
env.process(main_process(env))
env.run(100)
print('done')