dootask/app/Console/Commands/SyncTaskToSeekDB.php
kuaifan 1af29837e2 feat: 增加增量同步功能以优化 SeekDB 用户关系同步
- 在 SyncFileToSeekDB、SyncProjectToSeekDB 和 SyncTaskToSeekDB 中实现增量同步逻辑,支持只同步新增的用户关系。
- 新增 syncFileUsersIncremental、syncProjectUsersIncremental 和 syncTaskUsersIncremental 方法,提升数据同步效率。
- 更新相关命令行输出信息,以清晰指示同步状态和进度。
2025-12-31 09:28:10 +00:00

179 lines
5.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Console\Commands;
use App\Models\ProjectTask;
use App\Module\Apps;
use App\Module\SeekDB\SeekDBTask;
use App\Module\SeekDB\SeekDBKeyValue;
use Cache;
use Illuminate\Console\Command;
class SyncTaskToSeekDB extends Command
{
/**
* 更新数据
* --f: 全量更新 (默认)
* --i: 增量更新从上次更新的最后一个ID接上
* --u: 仅同步任务成员关系(不同步任务内容)
*
* 清理数据
* --c: 清除索引
*/
protected $signature = 'seekdb:sync-tasks {--f} {--i} {--c} {--u} {--batch=100}';
protected $description = '同步任务数据到 SeekDB';
/**
* @return int
*/
public function handle(): int
{
if (!Apps::isInstalled("seekdb")) {
$this->error("应用「SeekDB」未安装");
return 1;
}
// 注册信号处理器
if (extension_loaded('pcntl')) {
pcntl_async_signals(true);
pcntl_signal(SIGINT, [$this, 'handleSignal']);
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
}
// 检查锁
$lockInfo = $this->getLock();
if ($lockInfo) {
$this->error("命令已在运行中,开始时间: {$lockInfo['started_at']}");
return 1;
}
$this->setLock();
// 清除索引
if ($this->option('c')) {
$this->info('清除索引...');
SeekDBTask::clear();
SeekDBKeyValue::set('sync:seekdbTaskLastId', 0);
$this->info("索引删除成功");
$this->releaseLock();
return 0;
}
// 仅同步任务成员关系
if ($this->option('u')) {
$this->info('开始同步任务成员关系...');
$count = SeekDBTask::syncAllTaskUsers(function ($count) {
if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系...");
}
});
$this->info("任务成员关系同步完成,共 {$count}");
$this->releaseLock();
return 0;
}
$this->info('开始同步任务数据...');
$this->syncTasks();
// 同步任务成员关系
if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) {
// 全量同步:清空后重建
$this->info("\n全量同步任务成员关系...");
$count = SeekDBTask::syncAllTaskUsers(function ($count) {
if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系...");
}
});
$this->info("任务成员关系同步完成,共 {$count}");
} elseif ($this->option('i')) {
// 增量同步:只同步新增的
$this->info("\n增量同步任务成员关系...");
$count = SeekDBTask::syncTaskUsersIncremental(function ($count) {
if ($count % 1000 === 0) {
$this->info(" 已同步 {$count} 条关系...");
}
});
if ($count > 0) {
$this->info("新增任务成员关系 {$count}");
}
}
$this->info("\n同步完成");
$this->releaseLock();
return 0;
}
private function getLock(): ?array
{
$lockKey = md5($this->signature);
return Cache::has($lockKey) ? Cache::get($lockKey) : null;
}
private function setLock(): void
{
$lockKey = md5($this->signature);
Cache::put($lockKey, ['started_at' => date('Y-m-d H:i:s')], 600); // 任务可能较多10分钟
}
private function releaseLock(): void
{
Cache::forget(md5($this->signature));
}
public function handleSignal(int $signal): void
{
$this->releaseLock();
exit(0);
}
private function syncTasks(): void
{
$lastKey = "sync:seekdbTaskLastId";
$lastId = $this->option('i') ? intval(SeekDBKeyValue::get($lastKey, 0)) : 0;
if ($lastId > 0) {
$this->info("\n增量同步任务数据从ID: {$lastId}...");
} else {
$this->info("\n全量同步任务数据...");
}
// 只同步未归档的任务(包括软删除恢复的情况)
$query = ProjectTask::where('id', '>', $lastId)
->whereNull('archived_at');
$num = 0;
$count = $query->count();
$batchSize = $this->option('batch');
$total = 0;
do {
$tasks = ProjectTask::where('id', '>', $lastId)
->whereNull('archived_at')
->orderBy('id')
->limit($batchSize)
->get();
if ($tasks->isEmpty()) {
break;
}
$num += count($tasks);
$progress = $count > 0 ? round($num / $count * 100, 2) : 100;
$this->info("{$num}/{$count} ({$progress}%) 正在同步任务ID {$tasks->first()->id} ~ {$tasks->last()->id}");
$this->setLock();
$synced = SeekDBTask::batchSync($tasks);
$total += $synced;
$lastId = $tasks->last()->id;
SeekDBKeyValue::set($lastKey, $lastId);
} while (count($tasks) == $batchSize);
$this->info("同步任务结束 - 最后ID {$lastId},共同步 {$total} 个任务");
$this->info("已索引任务数量: " . SeekDBTask::getIndexedCount());
}
}