Running SimPy Until a Condition: Flexible Termination
<p>Sometimes you don't know when to stop. Run until the queue is empty. Until 1000 customers are served. Until something interesting happens.</p> <h2 id="basic-termination-methods">Basic Termination Methods</h2> <h3 id="run-until-time">Run Until Time</h3> <div class="code-block"><pre><span></span><code><span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span> <span class="c1"># Stop at time 100</span> </code></pre></div> <h3 id="run-until-process-completes">Run Until Process Completes</h3> <div class="code-block"><pre><span></span><code><span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">()</span> <span class="c1"># Run until all processes finish</span> </code></pre></div> <h3 id="run-until-event">Run Until Event</h3> <div class="code-block"><pre><span></span><code><span class="n">stop_event</span> <span class="o">=</span> <span class="n">env</span><span class="o">.</span><span class="n">event</span><span class="p">()</span> <span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="n">stop_event</span><span class="p">)</span> </code></pre></div> <h2 id="run-until-custom-condition">Run Until Custom Condition</h2> <p>Create a monitoring process that triggers termination:</p> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">stop_condition_monitor</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">stop_event</span><span class="p">,</span> <span class="n">condition_func</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Monitor until condition is true, then trigger stop."""</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">if</span> <span class="n">condition_func</span><span class="p">():</span> <span class="n">stop_event</span><span class="o">.</span><span class="n">succeed</span><span class="p">()</span> <span class="k">return</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># Check interval</span> <span class="c1"># Usage</span> <span class="n">stop_event</span> <span class="o">=</span> <span class="n">env</span><span class="o">.</span><span class="n">event</span><span class="p">()</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">stop_condition_monitor</span><span class="p">(</span> <span class="n">env</span><span class="p">,</span> <span class="n">stop_event</span><span class="p">,</span> <span class="n">condition_func</span><span class="o">=</span><span class="k">lambda</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">queue</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">server</span><span class="o">.</span><span class="n">count</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">))</span> <span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="n">stop_event</span><span class="p">)</span> </code></pre></div> <h2 id="run-until-n-customers-served">Run Until N Customers Served</h2> <div class="code-block"><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">SimulationController</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">env</span><span class="p">,</span> <span class="n">target_customers</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">env</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</span> <span class="o">=</span> <span class="n">target_customers</span> <span class="bp">self</span><span class="o">.</span><span class="n">served</span> <span class="o">=</span> <span class="mi">0</span> <span class="bp">self</span><span class="o">.</span><span class="n">done</span> <span class="o">=</span> <span class="n">env</span><span class="o">.</span><span class="n">event</span><span class="p">()</span> <span class="k">def</span><span class="w"> </span><span class="nf">record_service</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">served</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">served</span> <span class="o">>=</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">done</span><span class="o">.</span><span class="n">succeed</span><span class="p">()</span> <span class="n">controller</span> <span class="o">=</span> <span class="n">SimulationController</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">target_customers</span><span class="o">=</span><span class="mi">1000</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">customer</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">resource</span><span class="p">,</span> <span class="n">controller</span><span class="p">):</span> <span class="k">with</span> <span class="n">resource</span><span class="o">.</span><span class="n">request</span><span class="p">()</span> <span class="k">as</span> <span class="n">req</span><span class="p">:</span> <span class="k">yield</span> <span class="n">req</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="n">controller</span><span class="o">.</span><span class="n">record_service</span><span class="p">()</span> <span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="n">controller</span><span class="o">.</span><span class="n">done</span><span class="p">)</span> </code></pre></div> <h2 id="run-until-queue-empty">Run Until Queue Empty</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">queue_empty_monitor</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">resource</span><span class="p">,</span> <span class="n">stop_event</span><span class="p">,</span> <span class="n">check_interval</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Stop when queue and servers are both empty."""</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="c1"># Wait for warm-up</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">resource</span><span class="o">.</span><span class="n">queue</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">resource</span><span class="o">.</span><span class="n">count</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="n">stop_event</span><span class="o">.</span><span class="n">succeed</span><span class="p">()</span> <span class="k">return</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">check_interval</span><span class="p">)</span> <span class="n">stop</span> <span class="o">=</span> <span class="n">env</span><span class="o">.</span><span class="n">event</span><span class="p">()</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">queue_empty_monitor</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">server</span><span class="p">,</span> <span class="n">stop</span><span class="p">))</span> <span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="n">stop</span><span class="p">)</span> </code></pre></div> <h2 id="run-until-threshold-exceeded">Run Until Threshold Exceeded</h2> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">threshold_monitor</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">stats</span><span class="p">,</span> <span class="n">stop_event</span><span class="p">,</span> <span class="n">threshold</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Stop when average wait exceeds threshold."""</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="k">if</span> <span class="n">stats</span><span class="o">.</span><span class="n">wait_times</span><span class="p">:</span> <span class="n">avg_wait</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">stats</span><span class="o">.</span><span class="n">wait_times</span><span class="p">)</span> <span class="o">/</span> <span class="nb">len</span><span class="p">(</span><span class="n">stats</span><span class="o">.</span><span class="n">wait_times</span><span class="p">)</span> <span class="k">if</span> <span class="n">avg_wait</span> <span class="o">></span> <span class="n">threshold</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Threshold exceeded at </span><span class="si">{</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">}</span><span class="s2">: avg_wait = </span><span class="si">{</span><span class="n">avg_wait</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="n">stop_event</span><span class="o">.</span><span class="n">succeed</span><span class="p">()</span> <span class="k">return</span> </code></pre></div> <h2 id="combining-conditions">Combining Conditions</h2> <p>Stop on any of multiple conditions:</p> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">multi_condition_monitor</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">conditions</span><span class="p">,</span> <span class="n">stop_event</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Stop when any condition becomes true."""</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">check_func</span> <span class="ow">in</span> <span class="n">conditions</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="k">if</span> <span class="n">check_func</span><span class="p">():</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Stopping: </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="n">stop_event</span><span class="o">.</span><span class="n">succeed</span><span class="p">()</span> <span class="k">return</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="n">conditions</span> <span class="o">=</span> <span class="p">{</span> <span class="s1">'time_limit'</span><span class="p">:</span> <span class="k">lambda</span><span class="p">:</span> <span class="n">env</span><span class="o">.</span><span class="n">now</span> <span class="o">>=</span> <span class="mi">1000</span><span class="p">,</span> <span class="s1">'customers_served'</span><span class="p">:</span> <span class="k">lambda</span><span class="p">:</span> <span class="n">controller</span><span class="o">.</span><span class="n">served</span> <span class="o">>=</span> <span class="mi">500</span><span class="p">,</span> <span class="s1">'queue_exploded'</span><span class="p">:</span> <span class="k">lambda</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">queue</span><span class="p">)</span> <span class="o">></span> <span class="mi">100</span> <span class="p">}</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">multi_condition_monitor</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">conditions</span><span class="p">,</span> <span class="n">stop_event</span><span class="p">))</span> </code></pre></div> <h2 id="graceful-shutdown">Graceful Shutdown</h2> <p>Let in-progress work complete:</p> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">graceful_shutdown</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">resource</span><span class="p">,</span> <span class="n">stop_event</span><span class="p">,</span> <span class="n">grace_period</span><span class="o">=</span><span class="mi">50</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Signal stop, then wait for work to complete."""</span> <span class="c1"># Wait for stop signal</span> <span class="k">yield</span> <span class="n">stop_event</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Shutdown initiated at </span><span class="si">{</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="n">shutdown_started</span> <span class="o">=</span> <span class="n">env</span><span class="o">.</span><span class="n">now</span> <span class="c1"># Wait for queue to drain</span> <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">resource</span><span class="o">.</span><span class="n">queue</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">resource</span><span class="o">.</span><span class="n">count</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span> <span class="k">if</span> <span class="n">env</span><span class="o">.</span><span class="n">now</span> <span class="o">-</span> <span class="n">shutdown_started</span> <span class="o">></span> <span class="n">grace_period</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"Grace period expired, forcing shutdown"</span><span class="p">)</span> <span class="k">break</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Shutdown complete at </span><span class="si">{</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> </code></pre></div> <h2 id="step-by-step-execution">Step-by-Step Execution</h2> <p>Run one event at a time:</p> <div class="code-block"><pre><span></span><code><span class="n">env</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Environment</span><span class="p">()</span> <span class="c1"># ... setup processes</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">env</span><span class="o">.</span><span class="n">step</span><span class="p">()</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Time now: </span><span class="si">{</span><span class="n">env</span><span class="o">.</span><span class="n">now</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="k">if</span> <span class="n">some_condition</span><span class="p">():</span> <span class="k">break</span> <span class="k">except</span> <span class="n">simpy</span><span class="o">.</span><span class="n">EmptySchedule</span><span class="p">:</span> <span class="k">break</span> <span class="c1"># No more events</span> </code></pre></div> <h2 id="using-peek">Using peek()</h2> <p>Check next event without advancing:</p> <div class="code-block"><pre><span></span><code><span class="k">while</span> <span class="n">env</span><span class="o">.</span><span class="n">peek</span><span class="p">()</span> <span class="o"><</span> <span class="mi">100</span><span class="p">:</span> <span class="c1"># Next event before time 100</span> <span class="n">env</span><span class="o">.</span><span class="n">step</span><span class="p">()</span> <span class="c1"># Or check if anything is scheduled</span> <span class="k">if</span> <span class="n">env</span><span class="o">.</span><span class="n">peek</span><span class="p">()</span> <span class="o">!=</span> <span class="nb">float</span><span class="p">(</span><span class="s1">'inf'</span><span class="p">):</span> <span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="n">env</span><span class="o">.</span><span class="n">peek</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> </code></pre></div> <h2 id="timeout-fallback">Timeout Fallback</h2> <p>Always have a maximum run time:</p> <div class="code-block"><pre><span></span><code><span class="k">def</span><span class="w"> </span><span class="nf">run_with_limit</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">stop_condition</span><span class="p">,</span> <span class="n">max_time</span><span class="o">=</span><span class="mi">10000</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""Run until condition or max_time, whichever comes first."""</span> <span class="n">stop</span> <span class="o">=</span> <span class="n">env</span><span class="o">.</span><span class="n">event</span><span class="p">()</span> <span class="n">timeout</span> <span class="o">=</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">max_time</span><span class="p">)</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">condition_monitor</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">stop_condition</span><span class="p">,</span> <span class="n">stop</span><span class="p">))</span> <span class="n">result</span> <span class="o">=</span> <span class="k">yield</span> <span class="n">stop</span> <span class="o">|</span> <span class="n">timeout</span> <span class="k">if</span> <span class="n">stop</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"Condition met"</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"Max time reached"</span><span class="p">)</span> </code></pre></div> <h2 id="complete-example">Complete Example</h2> <div class="code-block"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">simpy</span> <span class="kn">import</span><span class="w"> </span><span class="nn">random</span> <span class="k">class</span><span class="w"> </span><span class="nc">TerminationController</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">env</span><span class="p">,</span> <span class="n">config</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">env</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span> <span class="o">=</span> <span class="n">config</span> <span class="bp">self</span><span class="o">.</span><span class="n">served</span> <span class="o">=</span> <span class="mi">0</span> <span class="bp">self</span><span class="o">.</span><span class="n">stop_event</span> <span class="o">=</span> <span class="n">env</span><span class="o">.</span><span class="n">event</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">stop_reason</span> <span class="o">=</span> <span class="kc">None</span> <span class="k">def</span><span class="w"> </span><span class="nf">record_service</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">served</span> <span class="o">+=</span> <span class="mi">1</span> <span class="bp">self</span><span class="o">.</span><span class="n">check_conditions</span><span class="p">()</span> <span class="k">def</span><span class="w"> </span><span class="nf">check_conditions</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">stop_event</span><span class="o">.</span><span class="n">triggered</span><span class="p">:</span> <span class="k">return</span> <span class="c1"># Check various conditions</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">served</span> <span class="o">>=</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'max_customers'</span><span class="p">,</span> <span class="nb">float</span><span class="p">(</span><span class="s1">'inf'</span><span class="p">)):</span> <span class="bp">self</span><span class="o">.</span><span class="n">stop</span><span class="p">(</span><span class="s1">'max_customers_reached'</span><span class="p">)</span> <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">now</span> <span class="o">>=</span> <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'max_time'</span><span class="p">,</span> <span class="nb">float</span><span class="p">(</span><span class="s1">'inf'</span><span class="p">)):</span> <span class="bp">self</span><span class="o">.</span><span class="n">stop</span><span class="p">(</span><span class="s1">'max_time_reached'</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">stop</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">reason</span><span class="p">):</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">stop_event</span><span class="o">.</span><span class="n">triggered</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">stop_reason</span> <span class="o">=</span> <span class="n">reason</span> <span class="bp">self</span><span class="o">.</span><span class="n">stop_event</span><span class="o">.</span><span class="n">succeed</span><span class="p">()</span> <span class="k">def</span><span class="w"> </span><span class="nf">time_checker</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">while</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">stop_event</span><span class="o">.</span><span class="n">triggered</span><span class="p">:</span> <span class="k">yield</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">check_conditions</span><span class="p">()</span> <span class="k">def</span><span class="w"> </span><span class="nf">run_simulation</span><span class="p">(</span><span class="n">config</span><span class="p">):</span> <span class="n">env</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Environment</span><span class="p">()</span> <span class="n">server</span> <span class="o">=</span> <span class="n">simpy</span><span class="o">.</span><span class="n">Resource</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">capacity</span><span class="o">=</span><span class="n">config</span><span class="p">[</span><span class="s1">'servers'</span><span class="p">])</span> <span class="n">controller</span> <span class="o">=</span> <span class="n">TerminationController</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">config</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">customer</span><span class="p">(</span><span class="n">name</span><span class="p">):</span> <span class="k">with</span> <span class="n">server</span><span class="o">.</span><span class="n">request</span><span class="p">()</span> <span class="k">as</span> <span class="n">req</span><span class="p">:</span> <span class="k">yield</span> <span class="n">req</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">5</span><span class="p">))</span> <span class="n">controller</span><span class="o">.</span><span class="n">record_service</span><span class="p">()</span> <span class="k">def</span><span class="w"> </span><span class="nf">arrivals</span><span class="p">():</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">while</span> <span class="ow">not</span> <span class="n">controller</span><span class="o">.</span><span class="n">stop_event</span><span class="o">.</span><span class="n">triggered</span><span class="p">:</span> <span class="k">yield</span> <span class="n">env</span><span class="o">.</span><span class="n">timeout</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">expovariate</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">4</span><span class="p">))</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">customer</span><span class="p">(</span><span class="sa">f</span><span class="s2">"C</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">"</span><span class="p">))</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">arrivals</span><span class="p">())</span> <span class="n">env</span><span class="o">.</span><span class="n">process</span><span class="p">(</span><span class="n">controller</span><span class="o">.</span><span class="n">time_checker</span><span class="p">())</span> <span class="n">env</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">until</span><span class="o">=</span><span class="n">controller</span><span class="o">.</span><span class="n">stop_event</span><span class="p">)</span> <span class="k">return</span> <span class="p">{</span> <span class="s1">'stop_reason'</span><span class="p">:</span> <span class="n">controller</span><span class="o">.</span><span class="n">stop_reason</span><span class="p">,</span> <span class="s1">'customers_served'</span><span class="p">:</span> <span class="n">controller</span><span class="o">.</span><span class="n">served</span><span class="p">,</span> <span class="s1">'final_time'</span><span class="p">:</span> <span class="n">env</span><span class="o">.</span><span class="n">now</span> <span class="p">}</span> <span class="c1"># Run with different termination conditions</span> <span class="n">result</span> <span class="o">=</span> <span class="n">run_simulation</span><span class="p">({</span> <span class="s1">'servers'</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s1">'max_customers'</span><span class="p">:</span> <span class="mi">500</span><span class="p">,</span> <span class="s1">'max_time'</span><span class="p">:</span> <span class="mi">1000</span> <span class="p">})</span> <span class="nb">print</span><span class="p">(</span><span class="n">result</span><span class="p">)</span> </code></pre></div> <h2 id="summary">Summary</h2> <p>Flexible termination: - Use events for custom stop conditions - Monitor processes to check conditions - Combine multiple conditions with AnyOf - Always have a fallback max time - Consider graceful shutdown for in-progress work</p> <p>Stop when it makes sense, not just when time runs out.</p> <h2 id="next-steps">Next Steps</h2> <ul> <li><a href="/blog_posts/simpy-environment-explained.html">SimPy Environment Explained</a></li> <li><a href="/blog_posts/simpy-run-multiple-replications.html">Running Multiple Replications</a></li> <li><a href="/blog_posts/simpy-collect-statistics.html">Collecting Statistics</a></li> </ul>Discover the Power of Simulation
Want to become a go-to expert in simulation with Python? The Complete Simulation Bootcamp will show you how simulation can transform your career and your projects.
Explore the Bootcamp