aol/offload 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

aol/offload

最新稳定版本:2.2.1

Composer 安装命令:

composer create-project aol/offload

包简介

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

README 文档

README

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

Build Status Coverage Status Code Climate Latest Stable Version Latest Unstable Version License

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?

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

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

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

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

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:

$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

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

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($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

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($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

Option Type
$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"

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 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

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

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

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

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

BSD-3-Clause

aol/offload 适用场景与选型建议

aol/offload 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 13.7k 次下载、GitHub Stars 达 10, 最近一次更新时间为 2015 年 09 月 29 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 aol/offload 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 aol/offload 我们能提供哪些服务?
定制开发 / 二次开发

基于 aol/offload 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 13.7k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 10
  • 点击次数: 25
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 10
  • Watchers: 21
  • Forks: 2
  • 开发语言: PHP

其他信息

  • 授权协议: BSD-3-Clause
  • 更新时间: 2015-09-29