1
0
mirror of https://github.com/danog/loop.git synced 2024-11-26 11:54:51 +01:00
Go to file
2023-01-22 21:59:13 +01:00
.github Cleanup 2022-12-24 17:48:33 +01:00
examples Remove signal loops 2023-01-22 21:59:13 +01:00
lib Remove signal loops 2023-01-22 21:59:13 +01:00
test Remove signal loops 2023-01-22 21:59:13 +01:00
.gitignore Refactoring 2022-12-24 17:24:51 +01:00
.php-cs-fixer.dist.php Refactoring 2022-12-24 17:24:51 +01:00
composer.json Cleanup 2022-12-24 14:37:39 +01:00
LICENSE First commit 2020-07-21 18:06:19 +02:00
phpunit.xml.dist Add resumeDeferOnce 2021-04-21 15:34:59 +02:00
psalm-baseline.xml Add baseline 2023-01-22 10:06:02 +01:00
psalm.xml Fix memory leak 2023-01-22 10:05:04 +01:00
README.md Remove signal loops 2023-01-22 21:59:13 +01:00

Loop

Build status codecov Psalm coverage License

danog/loop provides a set of powerful async loop APIs for executing operations periodically or on demand, in background loops a-la threads.
A more flexible and powerful alternative to AMPHP's repeat function, allowing dynamically changeable repeat periods and resumes.

Installation

composer require danog/loop

API

All loop APIs are defined by a set of interfaces: however, to use them, you would usually have to extend only one of the abstract class implementations.

Loop

Interface - Example

A basic loop, capable of running in background (asynchronously) the code contained in the loop function.

API:

namespace danog\Loop;

abstract class Loop
{
    abstract public function loop();
    abstract public function __toString(): string;
    
    public function start(): bool;
    public function isRunning(): bool;

    protected function startedLoop(): void;
    protected function exitedLoop(): void;
}

loop()

The loop async fiber will be run only once, every time the start method is called.

__toString()

This method should return the loop's name.
It's useful for implementing the log methods.

start()

Asynchronously starts the loop methods once in background.
Multiple calls to start will be ignored, returning false instead of true.

isRunning()

You can use the isRunning method to check if the loop is already running.

startedLoop()

Optionally, you can override this method to detect and log when the loop is started.
Make sure to always call the parent startedLoop() method to avoid issues.
You can use directly $this as loop name when logging, thanks to the custom __toString method.

exitedLoop()

Optionally, you can override this method to detect and log when the loop is ended.
Make sure to always call the parent exitedLoop() method to avoid issues.
You can use directly $this as loop name when logging, thanks to the custom __toString method.

ResumableLoop

Interface - Example

A way more useful loop that exposes APIs to pause and resume the execution of the loop, both from outside of the loop, and in a cron-like manner from inside of the loop.

namespace danog\Loop;

abstract class ResumableLoop extends Loop
{
    public function pause(?int $time = null): Future;
    public function resume(): Future;
}

All methods from Loop, plus:

pause()

Pauses the loop for the specified number of milliseconds, or forever if null is provided.

resume()

Forcefully resume the loop from the outside.
Returns a future that is resolved when the loop is paused again.

GenericLoop

Class - Example

If you want a simpler way to use the ResumableLoop, you can use the GenericLoop.

namespace danog\Loop\Generic;
class GenericLoop extends ResumableLoop
{
    /**
     * Stop the loop.
     */
    const STOP = -1;
    /**
     * Pause the loop.
     */
    const PAUSE = null;
    /**
     * Rerun the loop.
     */
    const CONTINUE = 0;
    /**
     * Constructor.
     *
     * @param callable $callable Callable to run
     * @param string   $name     Loop name
     */
    public function __construct(callable $callable, string $name);
    /**
     * Report pause, can be overriden for logging.
     *
     * @param integer $timeout Pause duration, 0 = forever
     *
     * @return void
     */
    protected function reportPause(int $timeout): void;
    /**
     * Get loop name, provided to constructor.
     */
    public function __toString(): string;
    /**
     * Stops loop.
     */
    public function stop(): void;
}

The return value of the callable can be:

  • A number - the loop will be paused for the specified number of seconds
  • GenericLoop::STOP - The loop will stop
  • GenericLoop::PAUSE - The loop will pause forever (or until the resume method is called on the loop object from outside the loop)
  • GenericLoop::CONTINUE - Return this if you want to rerun the loop without waiting

If the callable does not return anything, the loop will behave is if GenericLoop::PAUSE was returned.

PeriodicLoop

Class - Example

If you simply want to execute an action every N seconds, PeriodicLoop is the way to go.

namespace danog\Loop\Generic;

class PeriodicLoop extends ResumableLoop
{
    /**
     * Constructor.
     *
     * @param callable $callback Callback to call
     * @param string   $name     Loop name
     * @param ?int     $interval Loop interval
     */
    public function __construct(callable $callback, string $name, ?int $interval);
    /**
     * Get name of the loop, passed to the constructor.
     *
     * @return string
     */
    public function __toString(): string;
    /**
     * Stops loop.
     */
    public function stop(): void;
}

PeriodicLoop runs a callback at a periodic interval.
The loop can be stopped from the outside by using stop() and from the inside by returning true.