在缓存过期时更新DB?

时间:2016-12-28 18:16:40

标签: laravel caching memcached

我的用户表上有一个信用字段,每个用户请求对网站API递减1。 而不是在我考虑使用缓存的每个请求上读/写数据库。

所以在第一次请求时我抓住了积分,随后的请求我将缓存值减1,然后在某个时刻更新db ...

所以我创建了一个基本上做的中间件:

 public function handle($request, Closure $next)
    {

        // check api key
        $user = User::where(['api_token' => $request->input('license')])->first();
        if( ! $user )
            return \Response::json(['error' => 'The provided License key is not valid.'], 403);
        // check credits
        $cache_key = 'user_'.$user->id.'_credits';
        $credits = Cache::remember( $cache_key, 1, function ($u) use ($user) {
            return $u->credits;
        });
        $credits::decrement($cache_key);
        //update db on cache expiration ?


        return $next($request);
    }

但是现在我不确定何时应该使用新的缓存值更新数据库,或者这是否是一个很好的做法?

我基本上都试图在每次请求时通过缓存而不是数据库。

更新 检查@antonio后,我的功能会像下面的代码一样结束。我看到的问题是,在缓存过期之前,$ model->信用不会更新。但是我需要在每次通话时检查用户是否消耗了比他们更多的积分,或者看看我是否启动了自动购买活动。

public function handle($request, Closure $next)
{
    // Create a cache key based on the license
    $cache_key = 'user_'.($license = $request->input('license'));

    // Remember will return a cached user if the license is cached
    $model = Cache::remember($cache_key, 1, function () use ($license) {
        // find the user by the license
        if(! $user = User::where(['api_token' => $license])->first()) {
            // This license does not exists, return a response instead
            return \Response::json(['error' => 'The provided License key is not valid.'], 403);
        }

        // return the user or response
        return $user;
    });

    // If it is a response, break and return it
    if ($model instanceof Response || $model instanceof JsonResponse ) {
        return $model;
    }

    // TODO Validate domain
    //dd($_SERVER['HTTP_REFERER']); or use CORS or embed site_url in request?

    // Decrement the credits
    $model::decrement('credits');

    // Autobuy zone
    if( $model->credits == $model->auto_buy_amount )
        event( new CreditsLimitReached($model) );


    // No more credits
    if( $model->credits < 1 && ! $model->nocredits_email ){
        $model->nocredits_email = true;
        $model->save();
        // TODO clean no credits emails every day
        event( new OutOfCredits($model) );
        return \Response::json(['error' => 'You run out of credits.'], 403);
    }

    // Go to the next middleware
    return $next($request);
}

也许我的问题应该是你如何编写这样的代码。 基本上,当用户执行api调用时,我需要在此中间件上执行3个任务 1-减1学分 2-检查用户是否已达到自动购买区和火灾事件 3-检查用户是否用完了积分和火灾事件一次(基本上是电子邮件让他们知道用完了积分)

1 个答案:

答案 0 :(得分:1)

如果您需要在数据库中更新数据,那么您唯一能做的就是不要一遍又一遍地寻找用户来保存一个请求:

public function handle($request, Closure $next)
{
    // Create a cache key based on the license 
    $cache_key = 'user_'.($license = $request->input('license')).'_credits';

    // Remember will return a cached user if the license is cached 
    $model = Cache::remember($cache_key, 1, function () use ($license) {
        // find the user by the license
        if(! $user = User::where(['api_token' => $license])->first()) {
            // This license does not exists, return a response instead
            return \Response::json(['error' => 'The provided License key is not valid.'], 403);
        }

        // return the user
        return $user;
    });

    // If it is a response, break and return it
    if ($model instanceof Response) {
        return $model;
    }

    // Decrement the credits 
    $model::decrement('credits');

    // Go to the next middleware
    return $next($request);
}