diff --git a/src/IdResolvers/CacheResolver.php b/src/IdResolvers/CacheResolver.php index 1aa36b0..e24960b 100644 --- a/src/IdResolvers/CacheResolver.php +++ b/src/IdResolvers/CacheResolver.php @@ -2,7 +2,8 @@ namespace Glhd\Bits\IdResolvers; -use Illuminate\Cache\CacheManager; +use Illuminate\Contracts\Cache\LockProvider; +use Illuminate\Contracts\Cache\Store; use Illuminate\Support\DateFactory; use RuntimeException; @@ -11,7 +12,7 @@ class CacheResolver extends IdResolver protected ?int $value = null; public function __construct( - protected CacheManager $cache, + protected Store&LockProvider $cache, protected DateFactory $dates, protected int $max = 0b1111111111, ) { @@ -30,9 +31,10 @@ protected function acquire(): int return $this->cache->lock('glhd-bits-ids:lock') ->block(5, function() { - $reserved = $this->cache->get('glhd-bits-ids:reserved', fn() => []); + $reserved = $this->cache->get('glhd-bits-ids:reserved') ?? []; + $id = $this->firstAvailable($reserved) ?? $this->findExpired($reserved); - if ($id = $this->firstAvailable($reserved) ?? $this->findExpired($reserved)) { + if (null !== $id) { $reserved[$id] = $this->dates->now()->addHour()->unix(); $this->cache->forever('glhd-bits-ids:reserved', $reserved); return $id; diff --git a/src/Support/BitsServiceProvider.php b/src/Support/BitsServiceProvider.php index 37c633a..19fd444 100755 --- a/src/Support/BitsServiceProvider.php +++ b/src/Support/BitsServiceProvider.php @@ -40,7 +40,7 @@ public function register() $this->app->singleton(CacheResolver::class, function(Container $container) { $config = $container->make(Repository::class); - $cache = $container->make(CacheManager::class); + $cache = $container->make(CacheManager::class)->store(); $dates = $container->make(DateFactory::class); $format = $config->get('bits.format', 'snowflake'); diff --git a/tests/Unit/CacheIdResolverTest.php b/tests/Unit/CacheIdResolverTest.php new file mode 100644 index 0000000..2104ef7 --- /dev/null +++ b/tests/Unit/CacheIdResolverTest.php @@ -0,0 +1,65 @@ +assertEquals(0b00, $resolver->get(1, 1)->first()); + $this->assertEquals(0b00, $resolver->get(1, 1)->second()); + + Date::setTestNow(now()->addMinutes(10)); + + // Should get 0b01 + $resolver = new CacheResolver($store, app(DateFactory::class), 0b11); + $this->assertEquals(0b00, $resolver->get(1, 1)->first()); + $this->assertEquals(0b01, $resolver->get(1, 1)->second()); + + Date::setTestNow(now()->addMinutes(10)); + + // Should get 0b10 + $resolver = new CacheResolver($store, app(DateFactory::class), 0b11); + $this->assertEquals(0b01, $resolver->get(1, 1)->first()); + $this->assertEquals(0b00, $resolver->get(1, 1)->second()); + + Date::setTestNow(now()->addMinutes(10)); + + // Should get 0b11 + $resolver = new CacheResolver($store, app(DateFactory::class), 0b11); + $this->assertEquals(0b01, $resolver->get(1, 1)->first()); + $this->assertEquals(0b01, $resolver->get(1, 1)->second()); + + // Now we've run out of IDs… should throw + $this->assertThrows(function() use ($store) { + $resolver = new CacheResolver($store, app(DateFactory::class), 0b11); + $resolver->get(1, 1); + }, RuntimeException::class); + + Date::setTestNow(now()->addMinutes(30)); + + // 0b00 has not expired, so we should be able to acquire it + $resolver = new CacheResolver($store, app(DateFactory::class), 0b11); + $this->assertEquals(0b00, $resolver->get(1, 1)->first()); + $this->assertEquals(0b00, $resolver->get(1, 1)->second()); + + // But everything else is locked, so we should throw again + $this->assertThrows(function() use ($store) { + $resolver = new CacheResolver($store, app(DateFactory::class), 0b11); + $resolver->get(1, 1); + }, RuntimeException::class); + } +}