Skip to content

Commit

Permalink
feat: add a timeout for redis operations
Browse files Browse the repository at this point in the history
  • Loading branch information
bpolaszek committed Nov 6, 2023
1 parent ca716bf commit 3031b6d
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 17 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ To launch the hub with the Redis transport, change the `TRANSPORT_DSN` environme
TRANSPORT_DSN="redis://127.0.0.1:6379" ./bin/freddie
```

Optional parameters you can pass in the DSN's query string:
- `pingInterval` - regularly ping Redis connection, which will help detect outages (default `2.0`)
- `readTimeout` - max duration in seconds of a ping or publish request (default `null`)

_Alternatively, you can set this variable into `.env.local`._

## Advantages and limitations
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"nyholm/dsn": "^2.0",
"phpdocumentor/reflection-docblock": "^5.3",
"react/async": "^4.0.0",
"react/promise-timer": "^1.10",
"rize/uri-template": "^0.3.4",
"symfony/console": "^5.4.0|^6.0.0",
"symfony/dotenv": "^5.4.0|^6.0.0",
Expand Down
24 changes: 10 additions & 14 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ parameters:

ignoreErrors:
- '#React\\Promise\\PromiseInterface is not generic#'
- '#Unable to resolve the template type T in call to function React\\Promise\\Timer\\timeout#'
- '#Unable to resolve the template type T in call to function Freddie\\maybeTimeout#'
10 changes: 7 additions & 3 deletions src/Hub/Transport/Redis/RedisTransport.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@
use Generator;
use React\EventLoop\Loop;
use React\Promise\PromiseInterface;
use RuntimeException;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Throwable;

use function Freddie\maybeTimeout;
use function React\Async\await;
use function React\Promise\resolve;

Expand Down Expand Up @@ -45,6 +44,7 @@ public function __construct(
'channel' => 'mercure',
'key' => 'mercureUpdates',
'pingInterval' => 2.0,
'readTimeout' => null,
]);
$this->options = $resolver->resolve($options);
if ($this->options['pingInterval']) {
Expand All @@ -59,6 +59,7 @@ private function ping(): void
{
/** @var PromiseInterface $ping */
$ping = $this->redis->ping(); // @phpstan-ignore-line
$ping = maybeTimeout($ping, $this->options['readTimeout']);
$ping->then(
onRejected: Hub::die(...),
);
Expand All @@ -80,7 +81,10 @@ public function publish(Update $update): PromiseInterface
$this->init();
$payload = $this->serializer->serialize($update);

return $this->redis->publish($this->options['channel'], $payload) // @phpstan-ignore-line
/** @var PromiseInterface $promise */
$promise = $this->redis->publish($this->options['channel'], $payload); // @phpstan-ignore-line

return maybeTimeout($promise, $this->options['readTimeout'])
->then(fn () => $this->store($update))
->then(fn () => $update);
}
Expand Down
12 changes: 12 additions & 0 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
use Freddie\Helper\FlatQueryParser;
use Freddie\Helper\TopicHelper;
use Psr\Http\Message\ServerRequestInterface;
use React\Promise\PromiseInterface;

use function BenTools\QueryString\query_string;
use function in_array;
use function is_string;
use function React\Promise\Timer\timeout;
use function settype;
use function strtolower;
use function trim;
Expand Down Expand Up @@ -53,3 +55,13 @@ function extract_last_event_id(ServerRequestInterface $request): ?string
?? $qs->getParam('LAST-EVENT-ID')
?? null;
}

/**
* @template T
* @param PromiseInterface<T> $promise
* @return PromiseInterface<T>
*/
function maybeTimeout(PromiseInterface $promise, ?float $time = null): PromiseInterface
{
return null === $time ? $promise : timeout($promise, $time);
}

0 comments on commit 3031b6d

Please sign in to comment.