All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.qwlabs.tq.services.TaskQueue Maven / Gradle / Ivy

There is a newer version: 0.2.354
Show newest version
package com.qwlabs.tq.services;

import com.google.common.base.Throwables;
import com.qwlabs.tq.models.CleanupTaskQueueCommand;
import com.qwlabs.tq.models.ProcessStatus;
import com.qwlabs.tq.models.TaskQueueRecord;
import com.qwlabs.tq.repositories.TaskQueueRecordRepository;
import io.quarkus.narayana.jta.QuarkusTransaction;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.faulttolerance.Retry;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;

import static com.qwlabs.tq.models.TaskQueuePriorities.FAILED_TO_IDLE;
import static com.qwlabs.tq.models.TaskQueuePriorities.NEW;
import static com.qwlabs.tq.models.TaskQueuePriorities.POSTPONED_TO_IDLE;
import static com.qwlabs.tq.models.TaskQueuePriorities.PROCESSING_TIMEOUT;

@Slf4j
@ApplicationScoped
public class TaskQueue {

    private final TaskQueueRecordRepository repository;

    @Inject
    public TaskQueue(TaskQueueRecordRepository repository) {
        this.repository = repository;
    }

    public  void enqueue(final R record) {
        QuarkusTransaction.joiningExisting().run(() -> {
            record.setPriority(NEW);
            record.setProcessStatus(ProcessStatus.IDLE);
            record.setProcessStartAt(null);
            record.setProcessEndAt(null);
            repository.persist(record);
        });
    }

    @Retry(delay = 1, delayUnit = ChronoUnit.SECONDS)
    public void cleanup(CleanupTaskQueueCommand command) {
        command.getTopics().forEach(topic -> command.getStatuses().forEach(status -> {
            QuarkusTransaction.requiringNew().run(() -> {
                var count = repository.cleanup(topic, command.getBucket(), status);
                LOGGER.warn("Cleanup task queue count: {}", count);
            });
        }));
    }

    public void onBefore(final TaskQueueProcessContext context) {
        QuarkusTransaction.requiringNew().run(() -> {
            repository.resetByTimeout(context.getTopic(), context.getBucket(), Instant.now().minus(context.getTimeout()), PROCESSING_TIMEOUT);
            repository.resetByStatus(context.getTopic(), context.getBucket(), ProcessStatus.FAILED, POSTPONED_TO_IDLE);
            repository.resetByStatus(context.getTopic(), context.getBucket(), ProcessStatus.POSTPONED, FAILED_TO_IDLE);
        });
    }

    public  String poll(TaskQueueProcessContext context) {
        return QuarkusTransaction.requiringNew().call(() -> {
            boolean findCompleted;
            Optional mayRecord;
            do {
                mayRecord = repository.peekId(context.getTopic(), context.getBucket()).map(repository::lock);
                findCompleted = mayRecord.map(record -> record.getProcessStatus() == ProcessStatus.IDLE).orElse(true);
                LOGGER.info("task queue poll");
            } while (!findCompleted);
            mayRecord.ifPresent(record -> {
                record.setProcessStatus(ProcessStatus.PROCESSING);
                record.setProcessStartAt(Instant.now());
                record.setProcessEndAt(null);
                repository.persist(record);
            });
            return mayRecord.map(TaskQueueRecord::getId).orElse(null);
        });
    }

    public  void onWork(String recordId, Function processor) {
        QuarkusTransaction.requiringNew().run(() -> {
            R record = repository.lock(recordId);
            boolean succeed = processor.apply(record);
            record.setProcessStatus(succeed ? ProcessStatus.SUCCEED : ProcessStatus.POSTPONED);
            record.setProcessEndAt(Instant.now());
            repository.persist(record);
        });
    }

    public  void onFailed(TaskQueueProcessContext context,
                                                     String recordId,
                                                     Exception exception) {
        this.onFailed(context, recordId, exception, (r, e) -> LOGGER.error("Process task error. id={}", r.getId(), e));
    }

    public  void onFailed(TaskQueueProcessContext context,
                                                     String recordId,
                                                     Exception exception,
                                                     BiConsumer consumer) {
        QuarkusTransaction.requiringNew().run(() -> {
            R record = repository.lock(recordId);
            record.setFailedMessage(Throwables.getStackTraceAsString(exception));
            record.setProcessStatus(ProcessStatus.FAILED);
            record.setProcessEndAt(Instant.now());
            repository.persist(record);
            context.markFailedRecord(record.getId());
            consumer.accept(record, exception);
        });
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy