Rq: Pekerjaan dijalankan sebelum pekerjaan "depends_on" selesai saat menggunakan Job.create dan q.enqueue_job

Dibuat pada 27 Jan 2021  ·  5Komentar  ·  Sumber: rq/rq

Pertimbangkan cuplikan berikut di bawah ini dan dua pekerja yang sedang berjalan:

r = Redis(
    host="localhost",
    port=6379,
    db=0
)

q = Queue(connection=r)

id_1 = str(uuid4())

q.enqueue(func_1, job_id=id_1)
q.enqueue(func_2, depends_on=id_1)

Dalam cuplikan itu, semuanya berfungsi seperti yang diharapkan; kedua pekerjaan diantrekan ( satu di setiap pekerja ) tetapi func_2 tidak berjalan sebelum func_1 selesai.

Sekarang perhatikan cuplikan berikut, masih dengan dua pekerja:

r = Redis(
    host="localhost",
    port=6379,
    db=0
)

q = Queue(connection=r)

id_1 = str(uuid4())
id_2 = str(uuid4())

job_1 = Job.create(func_1, id=id_1, connection=r) 
job_2 = Job.create(func_2, id=id_2, depends_on=id_1, connection=r)
q.enqueue_job(job_1)
q.enqueue_job(job_2)

Ketika saya menjalankan kode itu, kedua pekerjaan segera dimulai, meskipun mengatur argumen depends_on .




Pertanyaan bonus mini

Mengapa perlu mengatur connection= pada pekerjaan saat saya menggunakan Job.create ? Bukankah instance Queue mengetahui koneksi Redis apa yang sudah digunakan? Kode gagal tanpa saya menyetel connection pada semua pekerjaan juga.

Komentar yang paling membantu

Saya pikir masalah ini harus dibuka kembali karena tampaknya masih terjadi (tes gagal baru):
https://github.com/rq/rq/blob/9bef2aa5a49d894bd03bd772b670e207f8edd0ef/tests/test_queue.py#L530

Saya setuju dengan @jtfidje bahwa ini tidak terkait dengan banyak dependensi, meskipun beberapa orang mendokumentasikannya di #1170.

Inti masalahnya adalah enqueue_job tidak memeriksa dependensi sama sekali.

Semua 5 komentar

PR ini menambahkan fitur multi ketergantungan ke RQ yang tepat. Anda harus mencoba ini sebagai gantinya.

Terimakasih telah menjawab!

Saya telah memeriksa PR, tetapi saya tidak dapat melihat bagaimana perubahan itu akan memperbaiki masalah ini? Satu-satunya cara saya berhasil memperbaikinya adalah dengan membuat kelas Antrian khusus dan mengimplementasikan fungsi berikut sebagai pengganti panggilan enqueue_job :

def enqueue_custom(
        self, job: CustomJob, pipeline=None, at_front: bool = False
    ) -> CustomJob:

        # If a _dependent_ job depends on any unfinished job, register all the
        # _dependent_ job's dependencies instead of enqueueing it.
        #
        # `Job#fetch_dependencies` sets WATCH on all dependencies. If
        # WatchError is raised in the when the pipeline is executed, that means
        # something else has modified either the set of dependencies or the
        # status of one of them. In this case, we simply retry.
        job.set_status(FlowStatus.QUEUED)

        if job._dependency_id:
            with self.connection.pipeline() as pipe:
                while True:
                    try:

                        pipe.watch(job.dependencies_key)

                        dependencies = job.fetch_dependencies(watch=True, pipeline=pipe)

                        pipe.multi()

                        for dependency in dependencies:
                            if (
                                dependency.get_status(refresh=False)
                                != FlowStatus.FINISHED
                            ):
                                job.set_status(FlowStatus.DEFERRED, pipeline=pipe)
                                job.register_dependency(pipeline=pipe)
                                job.save(pipeline=pipe)
                                job.cleanup(ttl=job.ttl, pipeline=pipe)
                                pipe.execute()
                                return job

                        break
                    except WatchError:
                        continue
        return super().enqueue_job(job, pipeline, at_front=at_front)

Anda juga memiliki if-block ini di dalam enqueue_call , dan saya tidak dapat membuat dependensi berfungsi tanpanya.

Dengan PR digabungkan, Anda dapat melakukan queue.enqueue(my_func, depends_on=[job_1, job_2])

Ya saya mengerti (dan sangat menyukai fitur ini!)
Tetapi, dalam dokumen Anda memberikan contoh ini:

from rq.job import Job

job = Job.create(count_words_at_url, 'http://nvie.com')
print('Job id: %s' % job.id)
q.enqueue_job(job)

# create a job with a predetermined id
job = Job.create(count_words_at url, 'http://nvie.com', id='my_job_id')

Cara melakukannya sesuai dengan kebutuhan saya _sangat_ baik, tetapi jika saya melakukan ini, dependensi pekerjaan tidak berfungsi. Jika ini berdasarkan desain maka tentu saja saya harus menggunakan q.enqueue( ... ) .

Sunting:
Fungsi saya (yaitu count_words_at_url ) dimuat secara dinamis dari file konfigurasi, dan oleh karena itu dilampirkan ke kelas Pekerjaan saya saat runtime.

Saya pikir masalah ini harus dibuka kembali karena tampaknya masih terjadi (tes gagal baru):
https://github.com/rq/rq/blob/9bef2aa5a49d894bd03bd772b670e207f8edd0ef/tests/test_queue.py#L530

Saya setuju dengan @jtfidje bahwa ini tidak terkait dengan banyak dependensi, meskipun beberapa orang mendokumentasikannya di #1170.

Inti masalahnya adalah enqueue_job tidak memeriksa dependensi sama sekali.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat