diff --git a/.gitignore b/.gitignore index 5ebc6bdca..0a5a18846 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ vars.yaml laravels.conf laravels.pid README_LOCAL.md +dootask.lock diff --git a/app/Console/Commands/SyncUserMsgToZincSearch.php b/app/Console/Commands/SyncUserMsgToZincSearch.php index b5662eebc..a9c9c1cbe 100644 --- a/app/Console/Commands/SyncUserMsgToZincSearch.php +++ b/app/Console/Commands/SyncUserMsgToZincSearch.php @@ -22,40 +22,64 @@ class SyncUserMsgToZincSearch extends Command protected $signature = 'zinc:sync-user-msg {--f} {--i} {--c} {--batch=1000}'; protected $description = '同步聊天会话用户和消息到 ZincSearch'; + /** + * 缓存锁实例 + */ + protected $lock; + /** * @return int */ public function handle(): int { + // 注册信号处理器(仅在支持pcntl扩展的环境下) + if (extension_loaded('pcntl')) { + pcntl_async_signals(true); // 启用异步信号处理 + pcntl_signal(SIGINT, [$this, 'handleSignal']); // Ctrl+C + pcntl_signal(SIGTERM, [$this, 'handleSignal']); // kill + } + // 使用缓存锁确保一次只能运行一个实例 - $lock = Cache::lock('zinc:sync-user-msg', 3600 * 6); // 锁定6小时 - if (!$lock->get()) { + $this->lock = Cache::lock('zinc:sync-user-msg', 3600 * 6); // 锁定6小时 + if (!$this->lock->get()) { $this->error('命令已在运行中,请等待当前实例完成'); return 1; } - try { - // 清除索引 - if ($this->option('c')) { - $this->info('清除索引...'); - ZincSearchKeyValue::clear(); - ZincSearchDialogMsg::clear(); - $this->info("索引删除成功"); - return 0; - } - - $this->info('开始同步聊天数据...'); - - // 同步消息数据 - $this->syncDialogMsgs(); - - // 完成 - $this->info("\n同步完成"); + // 清除索引 + if ($this->option('c')) { + $this->info('清除索引...'); + ZincSearchKeyValue::clear(); + ZincSearchDialogMsg::clear(); + $this->info("索引删除成功"); + $this->lock?->release(); return 0; - } finally { - // 确保无论如何都会释放锁 - $lock->release(); } + + $this->info('开始同步聊天数据...'); + + // 同步消息数据 + $this->syncDialogMsgs(); + + // 完成 + $this->info("\n同步完成"); + $this->lock?->release(); + return 0; + } + + /** + * 处理终端信号 + * + * @param int $signal + * @return void + */ + public function handleSignal(int $signal): void + { + // 释放锁 + if ($this->lock) { + $this->lock->release(); + } + exit(0); } /** @@ -65,16 +89,23 @@ class SyncUserMsgToZincSearch extends Command */ private function syncDialogMsgs(): void { - $this->info("\n同步消息数据..."); - // 获取上次同步的最后ID $lastKey = "sync:dialogUserMsgLastId"; $lastId = $this->option('i') ? intval(ZincSearchKeyValue::get($lastKey, 0)) : 0; + if ($lastId > 0) { + $this->info("\n同步消息数据({$lastId})..."); + } else { + $this->info("\n同步消息数据..."); + } + $num = 0; $count = WebSocketDialogMsg::where('id', '>', $lastId)->count(); $batchSize = $this->option('batch'); + $total = 0; + $lastNum = 0; + do { // 获取一批 $dialogMsgs = WebSocketDialogMsg::where('id', '>', $lastId) @@ -88,10 +119,14 @@ class SyncUserMsgToZincSearch extends Command $num += count($dialogMsgs); $progress = round($num / $count * 100, 2); - $this->info("{$num}/{$count} ({$progress}%) 正在同步消息ID {$lastId} ~ {$dialogMsgs->last()->id}"); + if ($progress < 100) { + $progress = number_format($progress, 2); + } + $this->info("{$num}/{$count} ({$progress}%) 正在同步消息ID {$dialogMsgs->first()->id} ~ {$dialogMsgs->last()->id} ({$total}|{$lastNum})"); // 同步数据 - ZincSearchDialogMsg::batchSync($dialogMsgs); + $lastNum = ZincSearchDialogMsg::batchSync($dialogMsgs); + $total += $lastNum; // 更新最后ID $lastId = $dialogMsgs->last()->id; diff --git a/app/Http/Controllers/IndexController.php b/app/Http/Controllers/IndexController.php index 0f3593a64..0a6c17744 100755 --- a/app/Http/Controllers/IndexController.php +++ b/app/Http/Controllers/IndexController.php @@ -23,7 +23,7 @@ use App\Tasks\AutoArchivedTask; use App\Tasks\DeleteBotMsgTask; use App\Tasks\CheckinRemindTask; use App\Tasks\CloseMeetingRoomTask; -use App\Tasks\ElasticSearchSyncTask; +use App\Tasks\ZincSearchSyncTask; use App\Tasks\UnclaimedTaskRemindTask; use Hhxsv5\LaravelS\Swoole\Task\Task; use Laravolt\Avatar\Avatar; @@ -259,8 +259,8 @@ class IndexController extends InvokeController Task::deliver(new UnclaimedTaskRemindTask()); // 关闭会议室 Task::deliver(new CloseMeetingRoomTask()); - // ElasticSearch 同步 - Task::deliver(new ElasticSearchSyncTask()); + // ZincSearch 同步 + Task::deliver(new ZincSearchSyncTask()); return "success"; } diff --git a/app/Module/ZincSearch/ZincSearchDialogMsg.php b/app/Module/ZincSearch/ZincSearchDialogMsg.php index 8b286687b..07a22ecaf 100644 --- a/app/Module/ZincSearch/ZincSearchDialogMsg.php +++ b/app/Module/ZincSearch/ZincSearchDialogMsg.php @@ -387,7 +387,7 @@ class ZincSearchDialogMsg } if ($dialogMsg->bot) { // 如果是机器人消息,跳过 - return true; + continue; } /** @var WebSocketDialogUser $dialogUser */ foreach ($userDialogs[$dialogMsg->dialog_id] as $dialogUser) { diff --git a/cmd b/cmd index 4d861e474..514ec09b0 100755 --- a/cmd +++ b/cmd @@ -457,8 +457,6 @@ if [ $# -gt 0 ]; then sleep 3 fi done - # 设置ES索引后缀 - env_set ES_INDEX_SUFFIX "$(rand_string 6)" # 启动容器 [[ "$(arg_get port)" -gt 0 ]] && env_set APP_PORT "$(arg_get port)" $COMPOSE up php -d @@ -479,7 +477,7 @@ if [ $# -gt 0 ]; then # 数据库迁移 run_exec php "php artisan migrate --seed" # 启动其他容器 - $COMPOSE up -d + $COMPOSE up -d --remove-orphans success "安装完成" info "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}" # 设置初始化密码 @@ -504,7 +502,7 @@ if [ $# -gt 0 ]; then run_exec php "php artisan migrate" run_exec nginx "nginx -s reload" restart_php - $COMPOSE up -d + $COMPOSE up -d --remove-orphans elif [[ "$1" == "uninstall" ]]; then shift 1 read -rp "确定要卸载(含:删除容器、数据库、日志)吗?(Y/n): " uninstall diff --git a/docker-compose.yml b/docker-compose.yml index d63ede0ff..00fdcd9f7 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -111,6 +111,7 @@ services: KK_OFFICE_PREVIEW_SWITCH_DISABLED: true KK_FILE_UPLOAD_ENABLED: true KK_MEDIA: "mp3,wav,mp4,mov,avi,wmv" + ES_JAVA_OPTS: "-Xmx1g" networks: extnetwork: ipv4_address: "${APP_IPPR}.7" @@ -229,6 +230,11 @@ services: ZINC_DATA_PATH: "/data" ZINC_FIRST_ADMIN_USER: "${DB_USERNAME}" ZINC_FIRST_ADMIN_PASSWORD: "${DB_PASSWORD}" + deploy: + resources: + limits: + cpus: '1' + memory: 1G networks: extnetwork: ipv4_address: "${APP_IPPR}.15" diff --git a/docker/es/config/elasticsearch.yml b/docker/es/config/elasticsearch.yml deleted file mode 100644 index 50b154702..000000000 --- a/docker/es/config/elasticsearch.yml +++ /dev/null @@ -1,2 +0,0 @@ -cluster.name: "docker-cluster" -network.host: 0.0.0.0 diff --git a/docker/es/data/.gitignore b/docker/es/data/.gitignore deleted file mode 100755 index d6b7ef32c..000000000 --- a/docker/es/data/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore