ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

Perl Background Job Queue Consumer

Perl

Goal -- WPM

Ready
Exercise Algorithm Area
1package Background::JobQueueConsumer;
2
3use strict;
4use warnings;
5
6# Simulate a job queue and job storage
7my @job_queue = ();
8my %job_status = (); # 'pending', 'processing', 'completed', 'failed'
9my $next_job_id = 1;
10
11sub add_job {
12my ($job_data) = @_;
13my $job_id = $next_job_id++;
14push @job_queue, { id => $job_id, data => $job_data };
15$job_status{$job_id} = 'pending';
16print "[Queue] Added job ID: $job_id\n";
17return $job_id;
18}
19
20sub process_next_job {
21# Check if there are any pending jobs
22my $job_to_process = undef;
23my $job_index = -1;
24
25for my $i (0 .. $#job_queue) {
26my $job = $job_queue[$i];
27if ($job_status{$job->{id}} eq 'pending') {
28$job_to_process = $job;
29$job_index = $i;
30last;
31}
32}
33
34# If no pending jobs, return immediately
35unless ($job_to_process) {
36# print "[Consumer] No pending jobs.\n";
37return;
38}
39
40# Mark job as processing
41$job_status{$job_to_process->{id}} = 'processing';
42print "[Consumer] Processing job ID: ", $job_to_process->{id}, ", Data: ", $job_to_process->{data}, "\n";
43
44# Simulate job processing (can fail)
45eval {
46# Simulate work
47sleep(1);
48
49# Simulate a 20% chance of failure
50if (rand() < 0.2) {
51die "Simulated job failure for ID ", $job_to_process->{id};
52}
53
54# If successful
55$job_status{$job_to_process->{id}} = 'completed';
56print "[Consumer] Job ID ", $job_to_process->{id}, " completed.\n";
57};
58
59if ($@) {
60# Job failed
61$job_status{$job_to_process->{id}} = 'failed';
62warn "[Consumer] Error processing job ID ", $job_to_process->{id}, ": $@";
63}
64
65# Remove processed job from queue (or mark as done)
66# For simplicity, we'll just remove it. In a real system, you might update status.
67if ($job_index != -1) {
68splice @job_queue, $job_index, 1;
69}
70}
71
72sub run_consumer {
73my ($duration_seconds) = @_;
74my $start_time = time;
75
76print "[Consumer] Starting consumer for ", $duration_seconds, " seconds...\n";
77
78while (time - $start_time < $duration_seconds) {
79process_next_job();
80# Sleep for a short interval to avoid busy-waiting
81sleep(0.5);
82}
83
84print "[Consumer] Consumer stopped.\n";
85# Report any remaining pending/processing jobs
86print "[Consumer] Final job statuses:\n";
87foreach my $job_id (keys %job_status) {
88print " - Job ID ", $job_id, ": ", $job_status{$job_id}, "\n";
89}
90}
91
92# Example Usage:
93# Background::JobQueueConsumer->add_job('send_email');
94# Background::JobQueueConsumer->add_job('generate_report');
95# Background::JobQueueConsumer->add_job('process_data');
96# Background::JobQueueConsumer->run_consumer(5); # Run for 5 seconds
Algorithm description viewbox

Perl Background Job Queue Consumer

Algorithm description:

This Perl script simulates a background job queue consumer. It maintains a simple in-memory queue of jobs and their statuses. The `add_job` function enqueues new tasks, and `process_next_job` attempts to pick up and execute a pending job. Job execution is simulated with a chance of failure, and statuses are updated accordingly ('pending', 'processing', 'completed', 'failed'). The `run_consumer` function polls the queue for a specified duration. This pattern is fundamental for building scalable applications that handle asynchronous tasks, such as sending emails, processing images, or generating reports.

Algorithm explanation:

The `Background::JobQueueConsumer` module simulates a basic job queue system. `add_job` adds a new job to the `@job_queue` array and initializes its status to 'pending' in the `%job_status` hash. `process_next_job` iterates through the queue to find the first 'pending' job. It marks the job as 'processing' and then uses an `eval` block to simulate the job execution. If the simulated work (or an explicit `die`) causes an exception within the `eval` block, the job is marked as 'failed', and the error is logged. Otherwise, it's marked 'completed'. The job is then removed from the queue. `run_consumer` repeatedly calls `process_next_job` at intervals for a given duration, preventing busy-waiting with `sleep`. Time complexity for `process_next_job` is O(Q) where Q is the current number of jobs in the queue, due to the linear scan. `run_consumer`'s complexity depends on the duration and the sleep interval, but each job processing is O(Q). Space complexity is O(J) where J is the number of jobs stored, for the queue and status hash.

Pseudocode:

Module Background::JobQueueConsumer:
  Global job_queue (array).
  Global job_status (hash).
  Global next_job_id (integer).

  Function add_job(job_data):
    Assign new job_id.
    Add {id: job_id, data: job_data} to job_queue.
    Set job_status[job_id] = 'pending'.
    Print "[Queue] Added job ID: job_id".
    Return job_id.

  Function process_next_job():
    job_to_process = null.
    job_index = -1.
    For each job in job_queue at index i:
      If job_status[job.id] is 'pending':
        job_to_process = job.
        job_index = i.
        Break loop.
    
    If job_to_process is null:
      Return.

    Set job_status[job_to_process.id] = 'processing'.
    Print "[Consumer] Processing job ID: job_to_process.id".

    Try:
      Simulate job work (e.g., sleep).
      If random chance of failure occurs:
        Die "Simulated job failure for ID job_to_process.id".
      Set job_status[job_to_process.id] = 'completed'.
      Print "[Consumer] Job ID job_to_process.id completed.".
    Catch exception:
      Set job_status[job_to_process.id] = 'failed'.
      Warn "[Consumer] Error processing job ID job_to_process.id: exception".

    If job_index is not -1:
      Remove job at job_index from job_queue.

  Function run_consumer(duration_seconds):
    start_time = current time.
    Print "[Consumer] Starting consumer...".

    While current time - start_time < duration_seconds:
      Call process_next_job().
      Sleep for 0.5 seconds.

    Print "[Consumer] Consumer stopped.".
    Print "[Consumer] Final job statuses:".
    For each job_id in job_status keys:
      Print "  - Job ID job_id: job_status[job_id]".