Skip to content

Releases: Julien-R44/bentocache

[email protected]

26 Dec 21:08

Choose a tag to compare

What's Changed

  • test: add testing documentation and improve test configuration by @thisisnkc in #90
  • fix: crossslot issue by @Julien-R44 in #96
  • fix(file): delete cache file if corrupted by @Julien-R44 in #97
  • fix: support for cluster with bus by @Julien-R44 in #98
  • Fix/lock timeout overrides timeout 0 by @Bnaya in #104
  • Fix syntax for pulling products from cache by @jln-brtn in #102
  • fix: standardize database credentials with environment variables and … by @thisisnkc in #100

New Contributors

Full Changelog: https://github.com/Julien-R44/bentocache/compare/[email protected]@1.5.1

[email protected]

20 Jul 22:55

Choose a tag to compare

What's Changed

  • Fix method name in documentation by @ZUHOWKS in #77
  • feat: add cache hits metric layer label by @psimk in #76
  • fix: enhance type support for CommonJS by @lzw1926 in #82
  • feat: add prune() method by @Julien-R44 in #85

New Contributors

  • @ZUHOWKS made their first contribution in #77
  • @psimk made their first contribution in #76
  • @lzw1926 made their first contribution in #82

Full Changelog: https://github.com/Julien-R44/bentocache/compare/[email protected]@1.5.0

[email protected]

19 May 22:42

Choose a tag to compare

Minor Changes

  • 2c5e4e7: Cleaner Worker Thread logs for the file driver now use the configured logger for better integration with structured logging systems

Patch Changes

  • 5941f90: Fix race condition with file driver writing corrupted data to disk
  • 5009b58: Fix bus synchronization issue when prefix is empty

Force Fresh + Namespace Clear fix

11 May 22:12

Choose a tag to compare

What's Changed

  • feat: add forceFresh option by @Julien-R44 in #70
  • fix: namespace clear doesn't use ioredis keyPrefix + namespace clear conflict by @ifullgaz in #68

New Contributors

Full Changelog: https://github.com/Julien-R44/bentocache/compare/[email protected]@1.3.0

Bugfixes

21 Apr 10:09

Choose a tag to compare

1.2.2

Patch Changes

  • c932ac5: Disable TTL Autopurge of memory driver. It allows to avoid overflow errors when a TTL of +25 days is set. See issue #61 for more information.
  • 0a2b25c: Fix has returning true on entries previously deleted by tag (see #64). The has method now relies on the driver's internal get method instead of has. This means the driver's has implementation is no longer used, and if you maintain a custom driver, you can safely remove it.
  • 6b01e1c: Fix knex driver throwing an error when quickly disconnecting from the database after application start. See adonisjs/cache#12 (comment)
  • 73d25cd: Update clear method to use SCAN instead of KEYS for non-blocking. Also replace del commands with unlink since this is non blocking.

What's Changed

  • fix: update clear method to use SCAN instead of KEYS for non-blocking by @Maged-Zaki in #62
  • fix: has returning true on entries deletedByTag by @Julien-R44 in #65

New Contributors

Full Changelog: https://github.com/Julien-R44/bentocache/compare/[email protected]@1.2.2

Experimental tagging support and other goodies

16 Feb 21:17

Choose a tag to compare

Bentocache 1.2.0

The main feature of this release is experimental tagging support!
Documentation available here https://bentocache.dev/docs/tagging
If you encounter any bugs with tags, please report them via Github issues !

Minor Changes

  • 8bb87b6: Add a new expire method.

    This method is slightly different from delete:

    When we delete a key, it is completely removed and forgotten. This means that even if we use grace periods, the value will no longer be available.

    expire works like delete, except that instead of completely removing the value, we just mark it as expired but keep it for the grace period. For example:

    // Set a value with a grace period of 6 minutes
    await cache.set({
      key: 'hello',
      value: 'world',
      grace: '6m',
    })
    
    // Expire the value. It is kept in the cache but marked as STALE for 6 minutes
    await cache.expire({ key: 'hello' })
    
    // Here, a get with grace: false will return nothing, because the value is stale
    const r1 = await cache.get({ key: 'hello', grace: false })
    
    // Here, a get with grace: true will return the value, because it is still within the grace period
    const r2 = await cache.get({ key: 'hello' })
    
    assert.deepEqual(r1, undefined)
    assert.deepEqual(r2, 'world')
  • d513fe2: Add a new E_L2_CACHE_ERROR. Before this commit, error happening when interacting with the L2 cache were not wrapped in a custom error. This is now the case. If needed, you can still access the original error by using the cause property of the E_L2_CACHE_ERROR error.

    import { errors } from 'bentocache'
    
    try {
      await cache.getOrSet({
        key: 'foo',
        factory: getFromDb(),
      })
    } catch (err) {
      if (err instanceof errors.E_L2_CACHE_ERROR) {
        console.error('An error happened while interacting with the L2 cache', err.cause)
      }
    }
  • 4d1feb5: Added a super simple circuit breaker system to the L2 Cache :

    • a l2CircuitBreakerDuration parameter to set the duration of the circuit breaker. How many seconds the circuit breaker will stay open.
    • If defined, the circuit breaker will open when a call to our distributed cache fails. It will stay open for l2CircuitBreakerDuration seconds.

    We may introduce more sophisticated circuit breaker system in the future, but for now, this simple system should be enough.

  • 6b1f42a: Enhance Factory Context by adding some new props.

    await cache.getOrSet({
      key: 'foo',
      factory: (ctx) => {
        // You can access the graced entry, if any, from the context
        if (ctx.gracedEntry?.value === 'bar') {
          return 'foo'
        }
    
        // You should now use `setOptions` to update cache entry options
        ctx.setOptions({
          tags: ['foo'],
          ttl: '2s',
          skipL2Write: true,
        })
    
        return 'foo'
      },
    })

    setTtl has been deprecated in favor of setOptions and will be removed in the next major version.

  • 73ac0fa: Add experimental tagging support. See #53

    await bento.getOrSet({
      key: 'foo',
      factory: getFromDb(),
      tags: ['tag-1', 'tag-2'],
    })
    
    await bento.set({
      key: 'foo',
      tags: ['tag-1'],
    })

    Then, we can delete all entries tagged with tag-1 using:

    await bento.deleteByTags({ tags: ['tag-1'] })

    As this is a rather complex feature, let's consider it experimental for now. Please report any bugs on Github issues

  • 6b1f42a: Add skipL2Write and skipBusNotify options.

    await cache.getOrSet({
      key: 'foo',
      skipL2Write: true,
      skipBusNotify: true,
      factory: () => 'foo',
    })

    When enabled, skipL2Write will prevent the entry from being written to L2 cache, and skipBusNotify will prevent any notification from being sent to the bus. You will probably never need to use these options, but they were useful for internal code, so decided to expose them.

  • b9db3b5: Rework the logs issued by bentocache to make them much cleaner, more consistent and make debug easier

Patch Changes

  • 491d12e: Handle deleteMany with empty keys list

[email protected]

09 Feb 01:06

Choose a tag to compare

This release primarily brings some huge performance boosts along with a few new features. Simply by installing this new version, you can enjoy up to 15x higher throughput in certain caching scenarios without any additional action required.

In some benchmarks of super common caching use-cases, we are up to 160x faster than cache-manager, the most popular caching library in Node.js ecosystem :

┌──────────────────────────────────┬────────────────────────┬─────────┐
│ Task name                        │ Throughput med (ops/s) │ Samples │
├──────────────────────────────────┼────────────────────────┼─────────┤
│ 'L1 GetOrSet - BentoCache''1062699 ± 20724'      │ 168254  │
│ 'L1 GetOrSet - CacheManager''5702 ± 176'           │ 1040    │
│ 'L2 GetOrSet - BentoCache''1823 ± 64'            │ 347     │
│ 'L2 GetOrSet - CacheManager''1455 ± 38'            │ 282     │
│ 'Tiered GetOrSet - BentoCache''1072961 ± 11637'      │ 174603  │
│ 'Tiered GetOrSet - CacheManager''5876 ± 80'            │ 1089    │
│ 'Tiered Get - BentoCache''1949318 ± 37272'      │ 1805048 │
│ 'Tiered Get - CacheManager''531350 ± 7789'        │ 496805  │
│ 'Tiered Set - BentoCache''2171 ± 45'            │ 2143    │
│ 'Tiered Set - CacheManager''2211 ± 84'            │ 2159    │
└──────────────────────────────────┴────────────────────────┴─────────┘

You can see the benchmarks here

New Features

  • 07224ba: Add two new functions in the factory callback context:

    cache.getOrSet({
      key: 'foo',
      factory: ({ skip, fail }) => {
        const item = await getFromDb()
        if (!item) {
          return skip()
        }
    
        if (item.isInvalid) {
          return fail('Item is invalid')
        }
    
        return item
      },
    })
    • Returning skip in a factory will not cache the value, and getOrSet will returns undefined even if there is a stale item in cache.
      It will force the key to be recalculated on the next call.

    • Returning fail in a factory will not cache the value and will throw an error. If there is a stale item in cache, it will be used.

    🔗 https://bentocache.dev/docs/methods#ctxskip

  • 2578357: Added a serialize: boolean option to the memory driver.

    If false, It means the data stored in the memory cache will not be serialized/parsed using JSON.stringify and JSON.parse. This allows for a much faster throughput but at the expense of:

    • not being able to limit the size of the stored data, because we can't really know the size of an unserialized object
    • Having inconsistent return between the L1 and L2 cache. The data stored in the L2 Cache will always be serialized because it passes over the network. Therefore, depending on whether the data is retrieved from the L1 and L2, we can have data that does not have the same form. For example, a Date instance will become a string if retrieved from the L2, but will remain a Date instance if retrieved from the L1. So, you should put extra care when using this feature with an additional L2 cache.

    🔗 https://bentocache.dev/docs/cache-drivers#serialize-option

v1.0.0

02 Feb 02:43

Choose a tag to compare

Upgrade Guide 1.0.0

Breaking Changes

Remove old syntax

We removed the "legacy" syntax and only keep the POJO-one.
For each method, the method signature is a full object, for example :

bento.get({ key: 'foo '})

timeouts

Previously you could define your timeouts like { soft: '200ms', hard: '2s' }. Now you should use the timeout and hardTimeout options like this:

getOrSet({ timeout: '200ms', hardTimeout: '2s' })

You can now also use 0 for timeout which means that, if a stale value is available, then it will be returned immediately, and the factory will run in the background. SWR-like, in short.

Default soft timeout

Now, the default timeout is 0. As explained above, this enables the SWR-like behavior by default, which is a good default for most cases and what most people expect. So make sure to update your code if you were relying on the previous default.

gracePeriod

  • gracePeriod is now grace and should be either false or a Duration.
  • If you were using the fallbackDuration option, you should now use the graceBackoff option at the root level.

suppressL2Errors

Previously, suppressL2Errors was automatically enabled even when we had just a L2 layer. Which can be confusing, because errors were filtered out. See #25

Now suppressL2Errors is a bit more intelligent and will only be enabled if you have a L1 layer. Unless you explicitly set it to true.

undefined values

Now, undefined values are forbidden in the cache. If you are trying to cache undefined, an error will be thrown. This is a breaking change because it was previously allowed.

If you want to cache something to represent the absence of a value, you can use null instead of undefined.

New Features

onFactoryError

Added an onFactoryError option that allows to catch errors that happen in factories, whether they are executed in background or not.

const result = await cache.getOrSet({
  key: 'foo',
  grace: '5s',
  factory: () => {
    throw new MyError()
  },
  onFactoryError: (error) => {
    // error is an instance of errors.E_FACTORY_ERROR
    // error.cause is the original error thrown by the factory
    // you can also check if the factory was executed in background with error.isBackgroundFactory
    // and also get the key with error.key. Will be `foo` in this case
  },
})

Memory driver options

The memory driver can now accept maxSize and maxEntrySize in human format. For example, maxSize: '1GB' or maxEntrySize: '1MB'.

We use https://www.npmjs.com/package/bytes for parsing so make sure to respect the format accepted by this module.

Re-worked the logic when only L2 is enabled

Previously, we were using a single piece of code to handle both scenarios, where only L2 is enabled and where both L1 and L2 are enabled. This was a bit confusing and led to some bugs.

Now, we have a clear separation between the two cases and we could fix some bugs that were present when only L2 was enabled.

[email protected]

09 Oct 21:49

Choose a tag to compare

Commits

  • refactor: Only one bus instance per named cache. All subsequent namespaces under it use the same bus. (3813247)
  • fixed return type for CacheStack namespace function (c772f83)
  • optimize: added namespace cache to CacheStack to avoid unnecessary creation of caches and buses (eaef9d8)
  • fix: clear message goes to all bus instances since channel name is the same (1699fe6)

What's Changed

  • fix: clear message goes to all bus instances + refactor: to optimize bus sync by @gkachru in #39

Full Changelog: https://github.com/Julien-R44/bentocache/compare/[email protected]@1.0.0-beta.12

[email protected]

04 Oct 21:47

Choose a tag to compare

What's Changed

  • fix: BinaryEncoding did not encode/decode the Clear message type by @gkachru in #38

Full Changelog: https://github.com/Julien-R44/bentocache/compare/[email protected]@1.0.0-beta.11