/** * Execute loop until *as.break()* is called * @param callable $func loop body callable( as ) * @param string $label optional label to use for *as.break()* and *as.continue()* in inner loops */ public function loop(callable $func, $label = null) { $this->_sanityCheck(); $loop_state = new \StdClass(); $loop_state->model_as = new \FutoIn\RI\AsyncSteps(); $loop_state->inner_as = null; $loop_state->outer_as = null; $loop_state->func = $func; $loop_state->label = $label; $this->add(function ($outer_as) use($loop_state) { $loop_state->outer_as = $outer_as; $create_iteration = function () use($outer_as, $loop_state) { $inner_as = new \FutoIn\RI\AsyncSteps($outer_as->state()); $inner_as->copyFrom($loop_state->model_as); $loop_state->inner_as = $inner_as; $inner_as->execute(); }; $loop_state->model_as->add(function ($as) use($loop_state) { $func = $loop_state->func; $func($as); }, function ($as, $err) use($loop_state) { if ($err === \FutoIn\Error::LoopCont) { $label = $loop_state->label; $term_label = $as->state()->_loop_term_label; if ($term_label && $term_label !== $label) { // Unroll loops continue \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $term_label) { try { $loop_state->outer_as->continueLoop($term_label); } catch (\Exception $e) { } }); } else { $as->success(); return; } } elseif ($err === \FutoIn\Error::LoopBreak) { $label = $loop_state->label; $term_label = $as->state()->_loop_term_label; if ($term_label && $term_label !== $label) { // Unroll loops and break \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $term_label) { try { $loop_state->outer_as->breakLoop($term_label); } catch (\Exception $e) { } }); } else { // Continue linear execution \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $term_label) { try { $loop_state->outer_as->success(); } catch (\Exception $e) { } }); } } else { \FutoIn\RI\AsyncTool::callLater(function () use($loop_state, $err) { try { $loop_state->outer_as->error($err); } catch (\Exception $e) { } }); } $loop_state->model_as->cancel(); $loop_state->model_as = null; $loop_state->func = null; })->add(function ($as) use($create_iteration) { \FutoIn\RI\AsyncTool::callLater($create_iteration); }); $outer_as->setCancel(function ($as) use($loop_state) { $loop_state->inner_as->cancel(); $loop_state->inner_as = null; if ($loop_state->model_as) { $loop_state->model_as->cancel(); $loop_state->model_as = null; } $loop_state->func = null; }); $create_iteration(); }); return $this; }
public function testCallParallel() { $this->as->add(function ($as) { $this->ccm->register($as, 'srv', 'srv.test:1.1', 'http://localhost:12345/ftn'); }); $this->as->run(); $model_as = new \FutoIn\RI\AsyncSteps(); $model_as->add(function ($as) { $iface = $this->ccm->iface('srv'); $iface->call($as, 'test', array('ping' => 'PINGPING')); }, function ($as, $err) { $as->executed = false; })->add(function ($as, $rsp) { $this->assertEquals('PONGPONG', $rsp->pong); $this->assertEquals('PINGPING', $rsp->ping); $as->executed = true; }); $asl = array(); for ($i = 0; $i < 10; ++$i) { $asl[] = clone $model_as; } foreach ($asl as $as) { $as->execute(); } \FutoIn\RI\AsyncToolTest::run(); foreach ($asl as $i => $as) { $this->assertTrue($as->executed, "Failed on {$i}"); } }
public function testModel() { $model_as = new \FutoIn\RI\AsyncSteps(); $model_as->model_run = false; $model_as->add(function ($as) { $as->model_run = true; $as->success(); }); $as = $this->as; $as->copyFrom($model_as); $as->add(function ($as) use($model_as) { $this->assertTrue($as->model_run); $as->model_run = false; $as->copyFrom($model_as); $as->successStep(); }); $as->execute(); AsyncToolTest::run(); $this->assertTrue($as->model_run); }