Отложенное выполнение php кода — стэк с таймаутами

Речь пойдет не о выполнении кода в потоке одного скрипта с таймаутами, а о задаче очередности некоего стека php кода в рамках некоего проекта с исполнением по таймаутам. Предположим есть некая строка в бд, которой необходимо проставить некий статус на заданное количество секунд и затем вернуть статусы на место. Напишем класс с функциями установки кода в стек, удаления кода из стека и выполнения кода по истечению таймаута. Код будем записывать в json файл, ключами массива сделаем microtime меточку и будем выполнять через eval вышедший по таймауту код:

<?php

class Phpstack
{
    public static $filename = 'phpstack.json';

    public static function set($code, $time)
    {
        $file = new SplFileObject(self::$filename, 'a+b');
        $file->flock(LOCK_EX);
        $file->rewind();
        $data = $file->fread($file->getSize());
        $data = $data ?: '[]';
        $arr = json_decode($data, true);
        $key = microtime(true) + $time;
        while (isset($arr[$key])) {
            $key = $key + 0.0001;
        }
        $key = (string)$key;
        $arr[$key] = $code;
        $file->ftruncate(0);
        $file->fwrite(json_encode($arr));
        $file->flock(LOCK_UN);
        return $key;
    }

    public static function remove($key)
    {
        $file = new SplFileObject(self::$filename, 'a+b');
        $file->flock(LOCK_EX);
        $file->rewind();
        $data = $file->fread($file->getSize());
        $data = $data ?: '[]';
        $arr = json_decode($data, true);
        if (isset($arr[$key])) {
            unset($arr[$key]);
        }
        $file->ftruncate(0);
        $file->fwrite(json_encode($arr));
        $file->flock(LOCK_UN);
    }

    public static function execute()
    {
        global $mysqli;
        $file = new SplFileObject(self::$filename, 'a+b');
        $file->flock(LOCK_EX);
        $file->rewind();
        $data = $file->fread($file->getSize());
        $data = $data ?: '[]';
        $arr = json_decode($data, true);
        $exec = false;
        foreach ($arr as $key => $value) {
            if ($key <= microtime(true)) {
                eval($value);
                unset($arr[$key]);
                $exec = true;
            }
        }
        if ($exec) {
            $file->ftruncate(0);
            $file->fwrite(json_encode($arr));
        }
        $file->flock(LOCK_UN);
    }
}

Функция set принимает в аргументах строку кода и таймаут в секундах, через который он должен быть исполнен. Возвращает установленный ключ —  для того чтобы код можно было в случае чего удалить без исполнения по данному ключу функцией remove. Функция execute исполняет вышедший из заданного таймаута стек кодов. Блокировкой файла мы исключаем возможность повторного исполнения одного и того же кода.

Использование, добавляем код в стек на 122 секунды:

$mysqli->query("UPDATE `questions` SET `section` = 12, `app_status` = 14 WHERE `id` = $id");
 Phpstack::set('$mysqli->query("UPDATE `questions` SET `section` = 7, `app_status` = 2 WHERE `id` = ' . $id . '");', 122);

А в индексном файле проекта пропишем исполнение:

Phpstack::execute();

глобальную $mysqli добавил потому что она требуется в текущем проекте для запроса в бд, у вас же её может не быть.

UPD: обновил код и добавил функцию executeKey($key)

Функция нужна для того, чтобы вызвать по ключу(ключ возвращается функцией set) код прямо здесь и сейчас(без учета таймаута). Т.е. функция remove просто удаляет заданный код по ключу, без выполнения, а функция executeKey выполняет и удаляет код.

<?php

class Phpstack
{
    public static $filename = 'phpstack.json';

    public static function set($code, $time)
    {
        $file = new SplFileObject(self::$filename, 'a+b');
        $file->flock(LOCK_EX);
        $file->rewind();
        $data = $file->fread($file->getSize());
        $data = $data ?: '[]';
        $arr = json_decode($data, true);
        $key = microtime(true) + $time;
        while (isset($arr[$key])) {
            $key = $key + 0.0001;
        }
        $key = (string)$key;
        $arr[$key] = $code;
        $file->ftruncate(0);
        $file->fwrite(json_encode($arr));
        $file->flock(LOCK_UN);
        return $key;
    }

    public static function remove($key)
    {
        $file = new SplFileObject(self::$filename, 'a+b');
        $file->flock(LOCK_EX);
        $file->rewind();
        $data = $file->fread($file->getSize());
        $data = $data ?: '[]';
        $arr = json_decode($data, true);
        if (isset($arr[$key])) {
            unset($arr[$key]);
        }
        $file->ftruncate(0);
        $file->fwrite(json_encode($arr));
        $file->flock(LOCK_UN);
    }

    public static function execute()
    {
        global $mysqli;
        $file = new SplFileObject(self::$filename, 'a+b');
        $file->flock(LOCK_EX);
        $file->rewind();
        $data = $file->fread($file->getSize());
        $data = $data ?: '[]';
        $arr = json_decode($data, true);
        $exec = false;
        foreach ($arr as $key => $value) {
            if ($key <= microtime(true)) {
                eval($value);
                unset($arr[$key]);
                $exec = true;
            }
        }
        if ($exec) {
            $file->ftruncate(0);
            $file->fwrite(json_encode($arr));
        }
        $file->flock(LOCK_UN);
    }

    public static function executeKey($key) {
        global $mysqli;
        $file = new SplFileObject(self::$filename, 'a+b');
        $file->flock(LOCK_EX);
        $file->rewind();
        $data = $file->fread($file->getSize());
        $data = $data ?: '[]';
        $arr = json_decode($data, true);
        if (isset($arr[$key])) {
            eval($arr[$key]);
            unset($arr[$key]);
        }
        $file->ftruncate(0);
        $file->fwrite(json_encode($arr));
        $file->flock(LOCK_UN);
    }
}

 

Оставить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *