1
0
forked from joey/godottest
Joey Eamigh 9989fab018
addons?
2025-10-10 14:07:23 -04:00

107 lines
3.1 KiB
GDScript

extends Node
class_name GedisWorker
## Processes jobs from a GedisQueue.
##
## A worker is responsible for fetching jobs from a specific queue and executing
## a processor function for each job.
##
## The processor function receives the job and is responsible for calling
## `job.complete()` or `job.fail()` to finish the job. The worker itself does
## not handle the return value of the processor.
signal completed(job: GedisJob, return_value)
signal failed(job: GedisJob, error_message: String)
signal progress(job: GedisJob, value: float)
signal _batch_completed
var _gedis_queue: GedisQueue
var _queue_name: String
var _processor: Callable
var _is_running = false
var _gedis: Gedis
var _jobs_in_progress = {}
var batch_size = 1
func _init(p_gedis_queue: GedisQueue, p_queue_name: String, p_processor: Callable, p_batch_size: int = 1):
_gedis_queue = p_gedis_queue
_gedis = _gedis_queue._gedis
_queue_name = p_queue_name
_processor = p_processor
batch_size = p_batch_size
_gedis_queue.completed.connect(_on_job_completed)
_gedis_queue.failed.connect(_on_job_failed)
_gedis_queue.progress.connect(func(job: GedisJob, value: float): progress.emit(job, value))
## Starts the worker.
func start():
_is_running = true
_process_jobs()
## Stops the worker.
func close():
_is_running = false
func _on_job_completed(job: GedisJob, return_value):
if _jobs_in_progress.has(job.id):
_jobs_in_progress.erase(job.id)
if _jobs_in_progress.is_empty():
_batch_completed.emit()
completed.emit(job, return_value)
func _on_job_failed(job: GedisJob, error_message: String):
if _jobs_in_progress.has(job.id):
_jobs_in_progress.erase(job.id)
if _jobs_in_progress.is_empty():
_batch_completed.emit()
failed.emit(job, error_message)
func _process_jobs():
await get_tree().process_frame
while _is_running:
if _gedis_queue.is_paused(_queue_name):
await get_tree().create_timer(1.0).timeout
continue
var job_ids = []
for i in range(batch_size):
var job_id = _gedis.lpop(_gedis_queue._get_queue_key(_queue_name, GedisQueue.STATUS_WAITING))
if not job_id:
break
job_ids.append(job_id)
if job_ids.is_empty():
if Engine.is_editor_hint():
await get_tree().process_frame
else:
if get_tree():
await get_tree().process_frame
continue
for job_id in job_ids:
_gedis.lpush(_gedis_queue._get_queue_key(_queue_name, GedisQueue.STATUS_ACTIVE), job_id)
var job = _gedis_queue.get_job(_queue_name, job_id)
if not job:
push_warning("GedisQueueWorker: Job with id %s not found." % job_id)
continue
_jobs_in_progress[job_id] = job
var job_key = _gedis_queue._get_job_key(_queue_name, job_id)
_gedis.hset(job_key, "status", GedisQueue.STATUS_ACTIVE)
_gedis_queue._gedis.publish(_gedis_queue._get_event_channel(_queue_name, "active"), {"job_id": job.id})
_process_job(job)
if not _jobs_in_progress.is_empty():
await _batch_completed
func _process_job(job: GedisJob):
var result = await _processor.call(job)
if result is Object and result.has_method("is_valid"):
result = await result
if job.status == GedisQueue.STATUS_ACTIVE:
job.complete(result)