Relay\Cluster subscribe method throwing Relay\Exception: Resource temporarily unavailable #163
-
With PHP 8.2 and Relay <?php
use Relay\Cluster;
$relayCluster = new Cluster(
"unprefixed-untracked",
["tcp://valkey-cluster-untracked:6372"],
5,
5,
false,
null,
[],
);
$relayCluster->subscribe(['abc'], function (): void {
echo 'subscribed';
}); Error: www-data@2ed6294b3a05:~/html$ php test-subscribe.php
[19-Feb-2025 10:00:40 EUROPE/LONDON] PHP Fatal error: Uncaught Relay\Exception: Resource temporarily unavailable (RELAY_ERR_REDIS; commands.c:7766) in /var/www/html/test-subscribe.php:15
Stack trace:
#0 /var/www/html/test-subscribe.php(15): Relay\Cluster->subscribe()
#1 {main}
thrown in /var/www/html/test-subscribe.php on line 15
[19-Feb-2025 10:00:40 EUROPE/LONDON] PHP Stack trace:
[19-Feb-2025 10:00:40 EUROPE/LONDON] PHP 1. newrelic_exception_handler($exception = class Relay\Exception { protected $message = 'Resource temporarily unavailable (RELAY_ERR_REDIS; commands.c:7766)'; private string ${Exception}string = 'Relay\\Exception: Resource temporarily unavailable (RELAY_ERR_REDIS; commands.c:7766) in /var/www/html/test-subscribe.php:15\nStack trace:\n#0 /var/www/html/test-subscribe.php(15): Relay\\Cluster->subscribe()\n#1 {main}'; protected $code = 14; protected string $file = '/var/www/html/test-subscribe.php'; protected int $line = 15; private array ${Exception}trace = [0 => [...]]; private ?Throwable ${Exception}previous = NULL }) Unknown:0 Here are the relay logs with log level debug: [1739959750.777437 DBG 355] shmalloc.c:301 Allocated 16777216 byte pool (head: 7a11ba281000, curr: 7a11ba282020, alignment: 16)
[1739959750.777501 DBG 355] cache.c:45 EPOCH[malloc]: 7a11ba288ec0 (5303 bytes)
[1739959750.777528 NOT 355] relay.c:2529 STARTUP - Relay has started...
[1739959750.778899 DBG 355] relay.c:3431 RINIT - Requests (1 total, 1 active, 1 max)
[1739959750.778982 DBG 355] relay.c:3395 HTTP_HOST - Failed to find HTTP_HOST or it's not a string
[1739959750.778986 DBG 355] relay.c:3370 PLINK - Uninstalling handlers for 0 links
[1739959750.781140 DBG 355] cache.c:45 EPOCH[malloc]: 7a11ba28e770 (4407 bytes)
[1739959750.781177 DBG 355] cache.c:2204 RDB - Adding new db 7a11ba28e640
[1739959750.781673 NOT 355] relay.c:3954 CRON TASKS - GC(keys): 1; GC(msg): 0, EVICTED: 0 keys
[1739959750.781690 NOT 355] relay.c:3962 CRON PROC - hits/miss: 0/0 (0.00%), oom: 0, errors: 0
[1739959750.781700 NOT 355] relay.c:3913 CRON STATS - Memory 59568/16777216 bytes (0.36%)
[1739959750.783966 DBG 355] cache.c:2352 ENDPOINT - releasing rdb (ep: 7a11ba28e4f0, rdb: 7a11ba28e640
[1739959750.784465 DBG 355] cache.c:45 EPOCH[malloc]: 7a11ba28fb60 (4407 bytes)
[1739959750.784496 DBG 355] cache.c:2204 RDB - Adding new db 7a11ba28fa30
[1739959756.052809 DBG 355] cache.c:2352 ENDPOINT - releasing rdb (ep: 7a11ba28f8e0, rdb: 7a11ba28fa30
[1739959756.053211 DBG 355] relay.c:3487 PID - Unregistering reader 7a11ba288dc0
[1739959756.053226 NOT 355] relay.c:3954 CRON TASKS - GC(keys): 1; GC(msg): 0, EVICTED: 0 keys
[1739959756.053230 NOT 355] relay.c:3962 CRON PROC - hits/miss: 0/0 (0.00%), oom: 0, errors: 0
[1739959756.053234 NOT 355] relay.c:3913 CRON STATS - Memory 64672/16777216 bytes (0.39%)
[1739959756.053252 DBG 355] relay.c:3313 PLINK - installing handlers for 0 links
[1739959756.053261 DBG 355] cache.c:321 ENDPOINT[0] - 'tcp://[email protected]:6373?cache=1&tracking=1' ep: 7a11ba28f8e0, rdb: 7a11ba28fa30 keys: 0
[1739959756.053265 DBG 355] cache.c:321 ENDPOINT[1] - 'tcp://[email protected]:6372?cache=1&tracking=1' ep: 7a11ba28e4f0, rdb: 7a11ba28e640 keys: 0
[1739959756.053269 DBG 355] relay.c:3522 RSHUTDOWN - Finished request
[1739959756.053487 NOT 355] relay.c:2559 MSHUTDOWN - Relay is shutting down, bye bye
This code has worked for me before, but very curiously, even when I tried downgrading gradually all the way down to relay I have tried both with cache enabled and with cache disabled, it made no difference. So I am wondering what other factor could have caused this.. PHP version:
Update: I have also tried rolling back to older docker images with PHP 8.2.13 but nothing seems to help - but at the same time I know for a fact that it worked before, and the code around it did not change in the meantime. Maybe some core OS libraries have been updated and now EAGAIN is produced during SUBSCRIBE where it was not the case before? I have tested with Debian Bullseye and Bookworm and issue seems to be happening on both. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
I have been able to retrieve strace for the script, here is the relevant part:
Full trace: relay-cluster-subscribe-strace.txt Here is some commentary fro o3-mini:Here’s what’s happening step-by-step: Sending the SUBSCRIBE command:379 sendto(7, "*2\r\n$9\r\nSUBSCRIBE\r\n$3\r\nabc\r\n", 28, 0, NULL, 0) = 28 Receiving the first response:379 recvfrom(7, ">3\r\n$9\r\nsubscribe\r\n$3\r\nabc\r\n:1\r\n", 16384, 0, NULL, NULL) = 32 Attempting to receive further data:379 recvfrom(7, 0x7fff233e5cc0, 16384, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) Socket closure:379 close(7) = 0 What This Means In a blocking socket: In a non‑blocking socket: Seems like if Relay is intentionally using non-blocking sockets, there needs to be special handling around the SUBSCRIBE family of commands. But it still does not answer my question why rolling back to previous versions of Relay had no impact. 🤔 |
Beta Was this translation helpful? Give feedback.
-
Hi 👋, This is just a read timeout. You can fix the specific use case by doing something like this: <?php
use Relay\Cluster;
use Relay\Relay;
$cluster = $argc > 1 ? $argv[1] : "tcp://valkey-cluster-untracked:6372";
$relayCluster = new Cluster(
"unprefixed-untracked",
[$cluster],
5,
5,
false,
null,
[],
);
// No timeout
$relayCluster->setOption(Relay::OPT_READ_TIMEOUT, 0);
$relayCluster->subscribe(['abc'], function (): void {
echo 'subscribed';
}); |
Beta Was this translation helpful? Give feedback.
-
@michael-grunder thanks for the answer, that helped! 👍 I have also noticed that trying to use the first argument passed into callback function leads to segfault: <?php
use Relay\Cluster;
use Relay\Relay;
$relayCluster = new Cluster(
"unprefixed-untracked",
["tcp://valkey-cluster-untracked:6372"],
3,
3,
false,
null,
);
// This is required otherwise subscribe will cause EAGAIN Resource temporarily unavailable error!
$relayCluster->setOption(Relay::OPT_READ_TIMEOUT, 0);
$relayCluster->subscribe(['123abc'], function (
/** @param Relay $relay This parameter cannot be typed or used - leads to segfault **/
$relay,
string $channel,
string $message,
): void {
echo 'Channel: ' . $channel . PHP_EOL;
echo 'MSG: ' . $message . PHP_EOL;
// segfault
echo get_class($relay) . PHP_EOL;
// no segfault
$x = func_get_arg(0);
// segfault
var_dump($x instanceof Relay);
}); This can be easily worked around by adding |
Beta Was this translation helpful? Give feedback.
Hi 👋,
This is just a read timeout. You can fix the specific use case by doing something like this: