private function reserveNextJobs(array $from_channels = null, $number_of_jobs_to_reserve = 1)
    {
        $reserved_job_ids = [];

        $timestamp = date('Y-m-d H:i:s');
        $channel_conditions = empty($from_channels) ? '' : $this->connection->prepareConditions(['`channel` IN ? AND ', $from_channels]);

        $limit = $number_of_jobs_to_reserve + 100;

        $job_ids = $this->connection->executeFirstColumn(
            'SELECT `id` 
                FROM `' . self::JOBS_TABLE_NAME . "` 
                WHERE {$channel_conditions}`reserved_at` IS NULL AND `available_at` <= ? 
                ORDER BY `priority` DESC, `id` 
                LIMIT 0, {$limit}",
            $timestamp
        );

        if (!empty($job_ids)) {
            foreach ($job_ids as $job_id) {
                $reservation_key = $this->prepareNewReservationKey();

                if ($this->on_reservation_key_ready) {
                    call_user_func($this->on_reservation_key_ready, $job_id, $reservation_key);
                }

                $this->connection->execute('UPDATE `' . self::JOBS_TABLE_NAME . '` SET `reservation_key` = ?, `reserved_at` = ? WHERE `id` = ? AND `reservation_key` IS NULL', $reservation_key, $timestamp, $job_id);

                if ($this->connection->affectedRows() === 1) {
                    $reserved_job_ids[] = $job_id;

                    if (count($reserved_job_ids) >= $number_of_jobs_to_reserve) {
                        break;
                    }
                }
            }
        }

        return $reserved_job_ids;
    }