PHPackages                             aol/offload - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Caching](/categories/caching)
4. /
5. aol/offload

AbandonedArchivedProject[Caching](/categories/caching)

aol/offload
===========

Simplify cached PHP tasks: background refresh, last-known-good, and single writer.

2.2.1(8y ago)1013.7k2BSD-3-ClausePHPPHP ^5.4 || ^7.0

Since Sep 29Pushed 6y ago21 watchersCompare

[ Source](https://github.com/aol/offload)[ Packagist](https://packagist.org/packages/aol/offload)[ RSS](/packages/aol-offload/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (4)Versions (29)Used By (0)

Offload
=======

[](#offload)

Simplify cached PHP tasks: background refresh, last-known-good, and single writer.

[![Build Status](https://camo.githubusercontent.com/460bb390e09e1e09cc49fbb097330444fceeeaaa1f44c7965adee8f20c25e36d/68747470733a2f2f7472617669732d63692e6f72672f616f6c2f6f66666c6f61642e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/aol/offload)[![Coverage Status](https://camo.githubusercontent.com/5e2b0fbc4dcbe0ffa8f99097ab392d98880e2d8b7bf009ac6820a75a4f629fc7/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f616f6c2f6f66666c6f61642f62616467652e7376673f6272616e63683d6d617374657226736572766963653d676974687562)](https://coveralls.io/github/aol/offload?branch=master)[![Code Climate](https://camo.githubusercontent.com/1d6dd892f0b891237698a4e985261f032bdbe6ca42a400c4b7d06b643ffdca42/68747470733a2f2f636f6465636c696d6174652e636f6d2f6769746875622f616f6c2f6f66666c6f61642f6261646765732f6770612e737667)](https://codeclimate.com/github/aol/offload)[![Latest Stable Version](https://camo.githubusercontent.com/fc23117918d1c57e8ac55d1128c513b21a3ab9c4d298955df5c739f1006c65be/68747470733a2f2f706f7365722e707567782e6f72672f616f6c2f6f66666c6f61642f762f737461626c65)](https://packagist.org/packages/aol/offload)[![Latest Unstable Version](https://camo.githubusercontent.com/3a0e792e73934e7d5e681bd18f4d27f3396ca191609ff9a69c31657d0b3753d9/68747470733a2f2f706f7365722e707567782e6f72672f616f6c2f6f66666c6f61642f762f756e737461626c65)](https://packagist.org/packages/aol/offload)[![License](https://camo.githubusercontent.com/0d24d27b5c26aa34880a11a8c693d03b1f9d7abe2af300846fd2ca3508bfde41/68747470733a2f2f706f7365722e707567782e6f72672f616f6c2f6f66666c6f61642f6c6963656e7365)](https://packagist.org/packages/aol/offload)

Example:

```
$offload = new OffloadManager(/* ... */);

// Fetch a result and repopulate it if necessary.
$data = $offload->fetch('task-key', function () {

  // Perform a time consuming task...
  return $data;

})->getData();
```

This will run a task in the background and cache the returned `$data` under the `task-key`. If the data is requested again, it will be returned immediately if in cache and a repopulation will be offload if the cache is stale.

How's This Work?
----------------

[](#hows-this-work)

Offload caches data with two timeframes, **fresh** and **stale**. These TTLs can be controlled using options, see **Offload Options**.

- **Fresh** (cache hit): Data is immediately returned with **no** repopulation.
- **Stale** (cache hit, stale): Data is immediately returned and a repopulation is queued.
- **No Data** (cache miss): Forces the repopulation to run immediately and that data is then cached and returned.

Offload uses a task queue to keep track of stale cache hits that need to be repopulated. When `$offload->drain()` is called, all tasks are run and the cache is repopulated. This is best to do once the request is completed so that the overhead of repopulating cache does not interfere with returning a response to the client quickly. See **Draining the Offload Queue**.

The `OffloadManager` can take any cache store implementing `OffloadCacheInterface`.

### Exclusive Tasks

[](#exclusive-tasks)

Tasks are run as `exclusive` by default. This behavior can be changed using options, see **Offload Options**.

Exclusive task repopulation means there will ever only be a single concurrent stale repopulation for a given key. This avoids the **rush to repopulate cache** that happens when a cached item expires.

The `OffloadManager` uses a lock implementation to provide this capability and can take any lock implementing `OffloadLockInterface`.

### Initialization

[](#initialization)

Here is an example of using a memcached instance for caching and a redis instance for locking:

```
// Setup a cache.
$cache = new OffloadCacheMemcached($memcached_instance);

// Setup a lock.
$lock = new OffloadLockRedis($predis_instance);

// Default options for offload manager:
$default_options = [
  'ttl_fresh'          => 5,    // Cache time in seconds
  'ttl_stale'          => 5,    // Stale cache time in seconds
  'exclusive'          => true, // Whether to run tasks exclusively by key (no concurrent repopulates for the same key)
  'background'         => true, // Whether to run tasks in the background
  'background_timeout' => 5,    // Timeout for exclusive background repopulates in seconds
];

// Create the offload manager.
$offload = new OffloadManager($cache, $lock, $default_options);
```

### Draining the Offload Queue

[](#draining-the-offload-queue)

To drain the offload queue properly, it is best to setup a PHP shutdown handler. This ensures the offload tasks will always be run at the end of the request. Example:

```
// ...

register_shutdown_function(function () use ($offload) {
  if ($offload->hasWork()) {

    // Flush all buffers.
    while (ob_get_level()) {
      ob_end_flush();
    }
    flush();

    // End the request if possible (under PHP FPM).
    if (function_exists('fastcgi_finish_request')) {
      fastcgi_finish_request();
    }

    // Run all tasks in the queue.
    $offload->drain();
  }
});
```

Deferreds
---------

[](#deferreds)

Offload supports returning deferred tasks from the repopulate callable. This allows several tasks to run in parallel when the offload queue is drained.

For example, using [Guzzle Async Requests](http://guzzle.readthedocs.org/en/latest/quickstart.html#async-requests):

```
$data = $offload->fetch('task-key', function () {

  // ...

  $promise = $guzzle_client->getAsync('http://www.example.com');

  return new OffloadDeferred([$promise, 'wait']);

})->getData();
```

The `OffloadDeferred` class takes a single callable that will wait for the result. In the above example, `$promise->wait()` waits for the HTTP request to complete and returns the result.

The repopulate callable can return any class that implements the `OffloadDeferredInterface`, so you can make adapters for custom async handling.

API
---

[](#api)

The `OffloadManager` implements `OffloadManagerInterface` and exposes the following methods:

`OffloadManager``fetch(...)`Fetch data from cache and repopulate if necessary.`fetchCached(...)`Same as `fetch(...)` with a specific fresh cache TTL.`queue(...)`Queue a task to run.`queueCached(...)`Same as `queue(...)` with a specific fresh cache TTL.`hasWork()`Whether the offload manager has work.`drain()`Drain the offload manager task queue.`getCache()`An object for interacting with the cache manually.See below for more details on the above methods.

See **Offload Options** for more information on the `$options` that can be provided. See **Offload Result** for more information on what `OffloadResult` details are returned.

### Fetching Data

[](#fetching-data)

#### `fetch`

[](#fetch)

`fetch($key, callable $repopulate, array $options = []): OffloadResult`

Check cache for data for the given `$key`. If the data is in cache, return it immediately. If the data is stale, schedule a repopulate to run when the offload manager is drained.

```
$result = $offload->fetch($key, function () {
  // Perform long running task...
  return $data;
});
```

#### `fetchCached`

[](#fetchcached)

`fetchCached($key, $ttl_fresh, callable $repopulate, array $options = []): OffloadResult`

Same as `fetch`. The following are equivalent:

```
$result = $offload->fetch($key, $repopulate, ['ttl_fresh' => 5]);
// is the same as:
$result = $offload->fetchCached($key, 5, $repopulate);
```

### Queuing Tasks

[](#queuing-tasks)

#### `queue`

[](#queue)

`queue($key, callable $repopulate, array $options = []): void`

Queue a repopuate task to be run. Do not check cache. Takes similar options as `fetch`.

#### `queueCached`

[](#queuecached)

`queueCached($key, $ttl_fresh, callable $repopulate, array $options = []): void`

Same as `queue`. The following are equivalent:

```
$result = $offload->queue($key, $repopulate, ['ttl_fresh' => 5]);
// is the same as:
$result = $offload->queueCached($key, 5, $repopulate);
```

### Fetch/Queue Arguments

[](#fetchqueue-arguments)

OptionType`$key``string`The key of the data to store.`$ttl_fresh``float`The fresh TTL in seconds for cached data. This is only provided to `fetchCached` and `queueCached`.`$repopulate``callable`A callable that returns data to repopulate cache.`$options``array`Options for the offload (see **Offload Options**).### Marking a Result as "Bad"

[](#marking-a-result-as-bad)

Sometimes results returned from a repopulate are not in a good state and *should not be cached*.

The offload manager provides a `OffloadRun` instance to the repopulate callable that can be used to mark the result as bad, for example:

```
$offload->fetch($key, function (OffloadRun $run) {

  // Get some data from a service...
  $object = $this->service->get($arguments);
  if (!$object->isValid()) {

    // If the data returned is not valid, mark the result as bad.
    // This will tell the offload manager *not to cache* the data.
    $run->setBad();

  }

});
```

### Offload Options

[](#offload-options)

Offload options are provided as an array, for example:

```
$options = [
  'ttl_fresh'  => 5,
  'ttl_stale'  => 10,
  'background' => true,
  // ...
];
$result = $offload->fetch($key, function () { /* ... */ }, $options);
```

Option`ttl_fresh`How long to cache data regarded as fresh in seconds. Fresh data is not repopulated. Defaults to `0`.`ttl_stale`How long to cache data regarded as stale in seconds. Stale data is repopulated when fetched. This value is *added to* the `ttl_fresh` to get a total cache time. Defaults to `5`.`exclusive`Whether to run the task exclusively (no other tasks for the same key can run concurrently). Defaults to `true`.`background`Whether to run the task in the background. This means it will wait until the offload manager is drained instead of repopulating immediately. Defaults to `true`.`background_timeout`How long to timeout exclusive background tasks in seconds. Defaults to `5`.`background_release_lock`Whether to release the repopulate lock as soon as the offloaded task is complete. Defaults to `true`. If set to `false`, offload will wait until the background timeout completes before allowing new repopulates.### Offload Result

[](#offload-result)

The `OffloadResult` class provides the following methods:

`OffloadResult``getData()`The data returned from the repopulate callable.`isFromCache()`Whether the data came from cache.`getExpireTime()`When the data from cache expires (unix time seconds).`getStaleTime()`How long the data has been stale in seconds. If the value is less than zero, that's how far it is from becoming stale.`isStale()`Whether the result is from cache, but is stale.Encoders
--------

[](#encoders)

By default, offload will use `OffloadEncoderStandard` (which does simple PHP serialization) to encode and decode data stored in cache. You can change this by implementing `OffloadEncoderInterface` and setting the encoder on the `OffloadManagerCache` instance.

```
class CustomEncoder implements OffloadEncoderInterface
{
    // ...

    public function encode($object)
    {
        // ... Encode the value ...
        return $string_value;
    }

    public function decode($string)
    {
        // ... Decode the value ...
        return $object_value;
    }
}

// ...

$offload = new OffloadManager(/* ... */);

// Change the encoder.
$offload->getCache()->setEncoder(new CustomEncoder(/* ... */));
```

By default offload will use the encoder you set to *decode* as well. You can change the decoding to use a separate instance by calling `setDecoder`:

```
$offload->getCache()->setEncoder(new FooEncoder(/* ... */));
$offload->getCache()->setDecoder(new BarEncoder(/* ... */));
```

### Encryption

[](#encryption)

Offload ships with an encryption encoder that leverages AES-256 encryption. It wraps any other encoder implementing `OffloadEncoderInterface` To use it simply set it as the encoder on the offload cache:

```
// Get the base encoder.
$base_encoder = $offload->getCache()->getEncoder();

// Wrap it with an encrypting encoder.
$encrypting_encoder = new OffloadEncoderEncryptedAes256(
    $base_encoder,
    // The key ID for the encryption.
    'foo',
    // Secret keys by ID. This enables key cycling.
    [
        'foo' => 'my_secret_key'
    ]
)

$offload->getCache()->setEncoder($encrypting_encoder);
```

#### Custom Encryption

[](#custom-encryption)

You can implement custom encryption by simply extending the abstract class `OffloadEncoderEncrypted`.

```
class CustomEncryptionEncoder extends OffloadEncoderEncrypted
{
    // ...

    protected function encrypt($string, $key)
    {
        // ... return encrypted string ..
    }

    protected function decrypt($string, $key)
    {
        // ... return decrypted string ..
    }
}
```

License
-------

[](#license)

[BSD-3-Clause](LICENSE)

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity30

Limited adoption so far

Community17

Small or concentrated contributor base

Maturity69

Established project with proven stability

 Bus Factor1

Top contributor holds 93.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~31 days

Total

28

Last Release

3028d ago

Major Versions

1.9.0 → 2.0.02017-08-25

PHP version history (2 changes)1.0.0PHP ^5.4

1.6.0PHP ^5.4 || ^7.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/7ce8cce0a2c987cbcfda65638dd5182c41eb7b1bb2271b2aad1660e173a38bc2?d=identicon)[ralouphie](/maintainers/ralouphie)

---

Top Contributors

[![ralouphie](https://avatars.githubusercontent.com/u/1500005?v=4)](https://github.com/ralouphie "ralouphie (58 commits)")[![shashikreddy](https://avatars.githubusercontent.com/u/762900?v=4)](https://github.com/shashikreddy "shashikreddy (2 commits)")[![baileylo](https://avatars.githubusercontent.com/u/145345?v=4)](https://github.com/baileylo "baileylo (1 commits)")[![stoph](https://avatars.githubusercontent.com/u/415988?v=4)](https://github.com/stoph "stoph (1 commits)")

---

Tags

offload-tasks

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/aol-offload/health.svg)

```
[![Health](https://phpackages.com/badges/aol-offload/health.svg)](https://phpackages.com/packages/aol-offload)
```

###  Alternatives

[react/cache

Async, Promise-based cache interface for ReactPHP

444112.4M40](/packages/react-cache)[wp-media/wp-rocket

Performance optimization plugin for WordPress

7431.3M3](/packages/wp-media-wp-rocket)[illuminate/cache

The Illuminate Cache package.

12835.6M1.4k](/packages/illuminate-cache)[colinmollenhour/php-redis-session-abstract

A Redis-based session handler with optimistic locking

6325.6M14](/packages/colinmollenhour-php-redis-session-abstract)[cheprasov/php-redis-client

Php client for Redis. It is a fast, fully-functional and user-friendly client for Redis, optimized for performance. RedisClient supports the latest versions of Redis starting from 2.6 to 6.0

1281.2M21](/packages/cheprasov-php-redis-client)[amphp/redis

Efficient asynchronous communication with Redis servers, enabling scalable and responsive data storage and retrieval.

165634.7k44](/packages/amphp-redis)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
