Async-Redis

 view release on metacpan or  search on metacpan

t/30-pipeline/auto-pipeline.t  view on Meta::CPAN

# t/30-pipeline/auto-pipeline.t
use strict;
use warnings;
use Test::Lib;
use Test::Async::Redis ':redis';
use Test2::V0;
use Async::Redis;
use Future;
use Time::HiRes qw(time);

SKIP: {
    my $redis = eval {
        my $r = Async::Redis->new(
            host => $ENV{REDIS_HOST} // 'localhost',
            connect_timeout => 2,
            auto_pipeline => 1,
        );
        run { $r->connect };
        $r;
    };
    skip "Redis not available: $@", 1 unless $redis;

    # Cleanup
    run { $redis->del(map { "ap:$_" } 1..100) };

    subtest 'auto-pipeline batches concurrent commands' => sub {
        # Fire 100 commands "at once"
        my @futures = map {
            $redis->set("ap:$_", $_)
        } (1..100);

        # Wait for all
        my @results = await_f(Future->needs_all(@futures));

        is(scalar @results, 100, 'all 100 completed');
        ok((grep { $_ eq 'OK' } @results) == 100, 'all returned OK');

        # Verify values
        my @get_futures = map { $redis->get("ap:$_") } (1..10);
        my @values = await_f(Future->needs_all(@get_futures));
        is(\@values, [1..10], 'values stored correctly');
    };

    subtest 'auto-pipeline transparent API' => sub {
        # Same API as non-pipelined
        my $result = run { $redis->set('ap:single', 'value') };
        is($result, 'OK', 'single command works');

        my $value = run { $redis->get('ap:single') };
        is($value, 'value', 'GET works');
    };

    subtest 'auto-pipeline faster than sequential' => sub {
        # Compare auto-pipelined to non-pipelined

        my $redis_no_ap = Async::Redis->new(
            host => $ENV{REDIS_HOST} // 'localhost',
            auto_pipeline => 0,  # disabled
        );
        run { $redis_no_ap->connect };

        # Sequential (no auto-pipeline)
        my $start = time();
        for my $i (1..50) {
            run { $redis_no_ap->set("ap:seq:$i", $i) };
        }
        my $sequential_time = time() - $start;

        # Auto-pipelined
        $start = time();
        my @futures = map { $redis->set("ap:batch:$_", $_) } (1..50);
        await_f(Future->needs_all(@futures));
        my $batched_time = time() - $start;

        ok($batched_time < $sequential_time,
            "Auto-pipeline (${batched_time}s) faster than sequential (${sequential_time}s)");

        # Cleanup
        await_f($redis->del(map { ("ap:seq:$_", "ap:batch:$_") } 1..50));
    };

    subtest 'auto-pipeline respects depth limit' => sub {
        my $redis_limited = Async::Redis->new(
            host => $ENV{REDIS_HOST} // 'localhost',
            auto_pipeline => 1,
            pipeline_depth => 50,
        );
        run { $redis_limited->connect };

        # Fire more commands than depth limit
        # Should batch into multiple pipelines automatically
        my @futures = map {
            $redis_limited->set("ap:depth:$_", $_)
        } (1..100);

        my @results = await_f(Future->needs_all(@futures));
        is(scalar @results, 100, 'all 100 completed despite depth limit');

        # Cleanup
        run { $redis->del(map { "ap:depth:$_" } 1..100) };
    };

    subtest 'non-blocking verification' => sub {
        my @futures = map { $redis->set("nb:autopipe:$_", $_) } (1..50);



( run in 0.560 second using v1.01-cache-2.11-cpan-f52f0507bed )