Async-Redis
view release on metacpan or search on metacpan
t/10-connection/timeout.t view on Meta::CPAN
SKIP: {
my $test_redis = eval {
my $r = Async::Redis->new(
host => $ENV{REDIS_HOST} // 'localhost',
connect_timeout => 2,
);
run { $r->connect };
$r;
};
skip "Redis not available: $@", 5 unless $test_redis;
$test_redis->disconnect;
subtest 'non-blocking verification' => sub {
my $redis = Async::Redis->new(
host => $ENV{REDIS_HOST} // 'localhost',
);
run { $redis->connect };
my @futures = map { $redis->set("nb:timeout:$_", $_) } (1..50);
my $start = time();
run { Future->needs_all(@futures) };
my $elapsed = time() - $start;
ok($elapsed < 5, "50 concurrent ops completed in ${elapsed}s");
run { $redis->del(map { "nb:timeout:$_" } 1..50) };
$redis->disconnect;
};
subtest 'request timeout fires on slow command' => sub {
my $redis = Async::Redis->new(
host => $ENV{REDIS_HOST} // 'localhost',
request_timeout => 0.3,
);
run { $redis->connect };
# Check if DEBUG command is available (not allowed in Docker Redis by default)
my $debug_available = eval { run { $redis->command('DEBUG', 'SLEEP', '0') }; 1 };
unless ($debug_available) {
$redis->disconnect;
plan skip_all => 'DEBUG command not available (requires enable-debug-command config)';
return;
}
my $start = time();
my $error;
eval {
# DEBUG SLEEP causes Redis to block for N seconds
run { $redis->command('DEBUG', 'SLEEP', '2') };
};
$error = $@;
my $elapsed = time() - $start;
ok($error, 'command failed');
like("$error", qr/timed?\s*out/i, 'error mentions timeout');
ok($elapsed >= 0.2, "waited at least 0.2s (got ${elapsed}s)");
ok($elapsed < 1.0, "timed out before command finished (got ${elapsed}s)");
$redis->disconnect;
};
subtest 'concurrent ops not blocked during request timeout' => sub {
my $redis = Async::Redis->new(
host => $ENV{REDIS_HOST} // 'localhost',
request_timeout => 5 * $TIMEOUT_SCALE,
);
run { $redis->connect };
my @futures = map { $redis->set("nb:req:timeout:$_", $_) } (1..50);
my $start = time();
run { Future->needs_all(@futures) };
my $elapsed = time() - $start;
ok($elapsed < 5, "50 concurrent ops completed in ${elapsed}s");
run { $redis->del(map { "nb:req:timeout:$_" } 1..50) };
$redis->disconnect;
};
subtest 'blocking command uses extended timeout' => sub {
my $redis = Async::Redis->new(
host => $ENV{REDIS_HOST} // 'localhost',
request_timeout => 1 * $TIMEOUT_SCALE,
blocking_timeout_buffer => 1 * $TIMEOUT_SCALE,
);
run { $redis->connect };
# Clean up any existing list
run { $redis->del('timeout:test:list') };
my $start = time();
# BLPOP with 0.5s server timeout
# Client deadline should be 0.5 + 1 (buffer) = 1.5s (scaled for slow environments)
my $result = run { $redis->command('BLPOP', 'timeout:test:list', '0.5') };
my $elapsed = time() - $start;
# BLPOP returns undef on timeout
is($result, undef, 'BLPOP returned undef (server timeout)');
ok($elapsed >= 0.4, "waited for server timeout (${elapsed}s)");
ok($elapsed < 1.0 * $TIMEOUT_SCALE, "didn't hit client timeout (${elapsed}s)");
$redis->disconnect;
};
subtest 'normal commands work within timeout' => sub {
my $redis = Async::Redis->new(
host => $ENV{REDIS_HOST} // 'localhost',
request_timeout => 5 * $TIMEOUT_SCALE,
);
run { $redis->connect };
# Normal commands should complete well within timeout
my $result = run { $redis->command('PING') };
is($result, 'PONG', 'PING works');
run { $redis->command('SET', 'timeout:test:key', 'value') };
my $value = run { $redis->command('GET', 'timeout:test:key') };
is($value, 'value', 'GET/SET work');
# Cleanup
run { $redis->del('timeout:test:key') };
$redis->disconnect;
};
( run in 0.664 second using v1.01-cache-2.11-cpan-df04353d9ac )