public OracleFetchedJob(OracleStorage storage, IDbConnection connection, FetchedJob fetchedJob)
        {
            if (fetchedJob == null)
            {
                throw new ArgumentNullException(nameof(fetchedJob));
            }

            _storage    = storage ?? throw new ArgumentNullException(nameof(storage));
            _connection = connection ?? throw new ArgumentNullException(nameof(connection));
            _id         = fetchedJob.Id;
            JobId       = fetchedJob.JobId.ToString(CultureInfo.InvariantCulture);
            Queue       = fetchedJob.Queue;
        }
        public IFetchedJob Dequeue(string[] queues, CancellationToken cancellationToken)
        {
            if (queues == null)
            {
                throw new ArgumentNullException(nameof(queues));
            }
            if (queues.Length == 0)
            {
                throw new ArgumentException("Queue array must be non-empty.", nameof(queues));
            }

            FetchedJob    fetchedJob = null;
            IDbConnection connection;

            do
            {
                cancellationToken.ThrowIfCancellationRequested();
                connection = _storage.CreateAndOpenConnection();

                try
                {
                    using (new OracleDistributedLock(_storage, "JobQueue", TimeSpan.FromSeconds(30)))
                    {
                        var token = Guid.NewGuid().ToString();

                        var nUpdated = connection.Execute(@"
UPDATE HF_JOB_QUEUE
   SET FETCHED_AT = SYS_EXTRACT_UTC (SYSTIMESTAMP), FETCH_TOKEN = :FETCH_TOKEN
 WHERE (FETCHED_AT IS NULL OR FETCHED_AT < SYS_EXTRACT_UTC (SYSTIMESTAMP) + numToDSInterval(:TIMEOUT, 'second' )) AND (QUEUE IN :QUEUES) AND ROWNUM = 1
",
                                                          new
                        {
                            QUEUES      = queues,
                            TIMEOUT     = _options.InvisibilityTimeout.Negate().TotalSeconds,
                            FETCH_TOKEN = token
                        });

                        if (nUpdated != 0)
                        {
                            fetchedJob =
                                connection
                                .QuerySingle <FetchedJob>(
                                    @"
 SELECT ID as Id, JOB_ID as JobId, QUEUE as Queue
   FROM HF_JOB_QUEUE
  WHERE FETCH_TOKEN = :FETCH_TOKEN
",
                                    new
                            {
                                FETCH_TOKEN = token
                            });
                        }
                    }
                }
                catch (DbException ex)
                {
                    Logger.ErrorException(ex.Message, ex);
                    _storage.ReleaseConnection(connection);
                    throw;
                }

                if (fetchedJob == null)
                {
                    _storage.ReleaseConnection(connection);

                    cancellationToken.WaitHandle.WaitOne(_options.QueuePollInterval);
                    cancellationToken.ThrowIfCancellationRequested();
                }
            } while (fetchedJob == null);

            return(new OracleFetchedJob(_storage, connection, fetchedJob));
        }