[TOC]
# 入隊
~~~
<?php
$redis = new Redis();
$redis->connect("127.0.0.1", "6379"); //php客戶端設置的ip及端口
$redis->auth('root'); //密碼
$redis->zAdd('goods:delay:task', time() + 50, json_encode(['id' => 1, 'cid' => 1, 'name' => 'php']));
$redis->zAdd('goods:delay:task', time() + 60, json_encode(['id' => 2, 'cid' => 2, 'name' => 'js']));
$redis->zAdd('goods:delay:task', time() + 70, json_encode(['id' => 3, 'cid' => 3, 'name' => 'py']));
/**
* 嘗試3秒內獲取鎖
* @param string $lockName
* @param int $timeout
* @return bool|string
*/
function acquireLock($lockName, $timeout = 3)
{
global $redis;
//唯一id
$identifier = uniqid();
//當前時間+3秒
$end = time() + $timeout;
//當這個時間大于等于當前時間就開始循環
while ($end >= time()) {
//設置鎖,key是鎖的名字,值是唯一id,只有鍵key不存在的時候才會設置key的值
//設置成功就返回唯一id
if ($redis->set($lockName, $identifier, ['nx'])) {
return $identifier;
}
//暫停1000微秒
usleep(1000);
}
return false;
}
/**
* 釋放鎖
* @param $lockName
* @param $identifier
* @return bool
*/
function releaseLock($lockName, $identifier)
{
global $redis;
while (true) {
//監控這個key的變化
$redis->watch($lockName);
//如果redis中獲取的這個key等于這個唯一ID
if ($redis->get($lockName) == $identifier) {
//開啟事務
$redis->multi(Redis::MULTI);
//刪除這個key
$redis->del($lockName);
//執行事務
$res = $redis->exec();
//如果事務返回值是存在,并且等于1,表示事務成功
if (isset($res[0]) && $res[0] == 1) {
return true;
}
} else {
//如果獲取的key不等于這個唯一索引
//取消監控
$redis->unwatch();
return false;
}
}
}
while (true) {
// 因為是有序集合,只要判斷第一條記錄的延時時間,例如第一條未到執行時間
// 相對說明集合的其他任務未到執行時間
//返回有序集 key 中,指定區間內的成員。其中成員的位置按 score 值遞增(從小到大)來排序
$rs = $redis->zRange('goods:delay:task', 0, 0, true);//["{"id":1,"cid":1,"name":"php"}" => 1512713765 ]
// 集合沒有任務,睡眠時間設置為5秒
if (empty($rs)) {
echo 'no tasks , sleep 5 seconds' . PHP_EOL;
sleep(5);
continue;
}
//獲得key
$taskJson = key($rs);//{"id":1,"cid":1,"name":"php"}
$delay = $rs[$taskJson];//獲得時間
//把存儲的json解析下來
$task = json_decode($taskJson, true);
$now = time();
// 到時間執行延時任務
if ($delay <= $now) {
// 對當前任務加鎖,避免移動移動延時任務到任務隊列時被其他客戶端修改
//加鎖成功會返回唯一id,不成功會返回false
if (!($identifier = acquireLock($task['id']))) {
continue;
}
// 移動延時任務到任務隊列
//刪,移除有序集key中的一個或多個成員,不存在的成員將被忽略
$redis->zRem('goods:delay:task', $taskJson);
//增,只能將一個值value插入到列表key的表尾
$redis->rPush('goods:task', $taskJson);
echo $task['id'] . ' run ' . PHP_EOL;
// 釋放鎖,執行完了開始釋放鎖
releaseLock($task['id'], $identifier);
} else {
// 延時任務未到執行時間
$sleep = $delay - $now;
// 最大值設置為2秒,保證如果有新的任務(延時時間1秒)進入集合時能夠及時的被處理
// $sleep = $sleep > 2 ? 2 :$sleep;
echo 'wait ' . $sleep . ' seconds ' . PHP_EOL;
sleep($sleep);
}
}
~~~
# 出隊
~~~
<?php
$redis = new Redis();
$redis->connect("127.0.0.1", "6379"); //php客戶端設置的ip及端口
$redis->auth('root'); //密碼
// 出隊
while (true) {
// 阻塞設置超時時間為3秒
//刪除和獲取列表中的第一個元素,或阻塞直到有可用
$task = $redis->blPop(['goods:task'], 3);
if ($task) {
$redis->rPush('goods:success:task', $task[1]);
$task = json_decode($task[1], true);
echo $task['id'] . ':' . $task['cid'] . ':' . 'handle success';
echo PHP_EOL;
} else {
echo 'nothing' . PHP_EOL;
sleep(5);
}
}
~~~
- 配置
- composer安裝
- composer用法
- composer版本約束表達
- phpstorm
- sftp文件同步
- php類型約束
- laradock
- 配置文件緩存詳解
- git
- 自定義函數
- 核心概念
- IOC
- 服務提供者
- Facade
- 契約
- 生命周期
- 路由
- 請求
- 命名路由
- 路由分組
- 資源路由
- 控制器路由
- 響應宏
- 響應
- Command
- 創建命令
- 定時任務
- console路由
- 執行用戶自定義的定時任務
- artisan命令
- 中間件
- 創建中間件
- 使用中間件
- 前置和后置
- 詳細介紹
- 訪問次數限制
- 為 VerifyCsrfToken 添加過濾條件
- 單點登錄
- 事件
- 創建
- ORM
- 簡介
- DB類
- 配置
- CURD
- queryScope和setAttribute
- 查看sql執行過程
- 關聯關系
- 一對一
- 一對多
- 多對多
- 遠程關聯
- 多態一對多
- 多態多對多
- 關聯數據庫的調用
- withDefault
- 跨模型更新時間戳
- withCount,withSum ,withAvg, withMax,withMin
- SQL常見操作
- 模型事件
- 模型事件詳解
- 模型事件與 Observer
- deleted 事件未被觸發
- model validation
- ORM/代碼片段
- Repository模式
- 多重where語句
- 中間表類型轉換
- Collection集合
- 新增的一些方法
- 常見用法
- 求和例子
- 機場登機例子
- 計算github活躍度
- 轉化評論格式
- 計算營業額
- 創建lookup數組
- 重新組織出表和字段關系并且字段排序
- 重構循環
- 其他例子
- 其他問題一
- 去重
- 第二個數組按第一個數組的鍵值排序
- 搜索ES
- 安裝
- 表單
- Request
- sessiom
- Response
- Input
- 表單驗證
- 簡介
- Validator
- Request類
- 接口中的表單驗證
- Lumen 中自定義表單驗證返回消息
- redis
- 廣播事件
- 發布訂閱
- 隊列
- 守護進程
- redis隊列的坑
- beanstalkd
- rabbitmq
- redis隊列
- 日志模塊
- 錯誤
- 日志詳解
- 數據填充與遷移
- 生成數據
- 數據填充seed
- migrate
- 常見錯誤
- Blade模板
- 流程控制
- 子視圖
- URL
- 代碼片段
- Carbon時間類
- 一些用法
- 郵件
- 分頁
- 加密解密
- 緩存
- 文件上傳
- 優化
- 隨記
- 嵌套評論
- 判斷字符串是否是合法的 json 字符串
- 單元測試
- 計算出兩個日期的diff
- 自定義一個類文件讓composer加載
- 時間加減
- 對象數組互轉方法
- 用戶停留過久自動退出登錄
- optional 輔助方法
- 文件下載
- Api
- Dingo api
- auth.basic
- api_token
- Jwt-Auth
- passport
- Auth
- Authentication 和 Authorization
- Auth Facade
- 授權策略
- Gates
- composer包
- debug包
- idehelp包
- image處理
- 驗證碼
- jq插件
- 第三方登錄
- 第三方支付
- log顯示包
- 微信包
- xss過濾
- Excel包
- MongoDB
- php操作
- 聚合查詢
- 發送帶附件郵件
- 中文轉拼音包
- clockwork網頁調試
- emoji表情
- symfony組件
- swooletw/laravel-swoole
- 常見問題
- 跨域問題
- Laravel隊列優先級的一個坑
- cache:clear清除緩存問題
- .env無法讀取
- 源碼相關基礎知識
- __set和__get
- 依賴注入、控制反轉和依賴倒置原則
- 控制反轉容器(Ioc Container)
- 深入服務容器
- call_user_func
- compact
- 中間件簡易實現
- array_reduce
- 中間件實現代碼
- Pipeline管道操作
- composer自動加載
- redis延時隊列
- 了解laravel redis隊列
- cli
- 源碼解讀
- Facade分析
- Facade源碼分析
- IOC服務容器
- 中間件原理
- 依賴注入淺析
- 微信
- 微信公眾號
- 常用接收消息
- 6大接收接口
- 常用被動回復消息
- 接口調用憑證
- 自定義菜單
- 新增素材
- 客服消息
- 二維碼
- 微信語音
- LBS定位
- 網頁授權
- JSSDK
- easywechat
- 小程序
- 小程序配置app.json