main: 优化消息处理逻辑与 Redis 发布

- 调整消息解析流程,支持 JSON 解码与模型实例化
- 增加 `appendMessage` 方法的保存控制参数
- 修复因保存控制导致的重复发布问题
- 优化 Redis 发布逻辑,支持消息内容推送
- 更新注释与待优化标记,提升代码可读性
This commit is contained in:
2025-12-19 12:53:53 +08:00
parent 8c4ad80dab
commit dcbd0338e6
3 changed files with 14 additions and 7 deletions

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Http\Resources\MessageResource;
use App\Models\Message;
use App\Services\ChatService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@@ -72,7 +73,8 @@ class ChatSessionSseController extends Controller
return;
}
$msg = $this->service->getMessage($sessionId, $payload);
$msg = json_decode($payload, true, 512, JSON_THROW_ON_ERROR);
$msg = new Message($msg);
if ($msg && $msg->seq > $lastSentSeq) {
if ($msg->seq > $lastSentSeq + 1) {
$this->sendBacklog($sessionId, $lastSentSeq, $limit);

View File

@@ -59,13 +59,13 @@ class ChatService
* @param bool|null $wasDeduped 是否发生了去重(可选,按引用返回)
* @return Message 返回成功追加的消息实例。如果存在去重键并已存在重复消息,则返回现有的消息。
*/
public function appendMessage(array $dto, ?bool &$wasDeduped = null): Message
public function appendMessage(array $dto, ?bool &$wasDeduped = null, bool $save = true): Message
{
$messageRef = null;
$isNew = false;
$wasDeduped = false;
DB::transaction(function () use ($dto, &$messageRef, &$isNew, &$wasDeduped) {
DB::transaction(function () use ($dto, &$messageRef, &$isNew, &$wasDeduped, $save) {
/** @var ChatSession $session */
$session = ChatSession::query()
->whereKey($dto['session_id'])
@@ -104,7 +104,9 @@ class ChatService
]);
try {
if ($save) {
$message->save();
}
$isNew = true;
} catch (QueryException $e) {
if ($this->isUniqueConstraint($e) && $dedupeKey) {
@@ -131,8 +133,10 @@ class ChatService
$messageRef = $message;
if ($isNew) {
if ($isNew && $save) {
DB::afterCommit(fn () => $this->publishMessageAppended($message));
} else {
$this->publishMessageAppended($message);
}
});
@@ -290,7 +294,8 @@ class ChatService
$channel = "session:{$message->session_id}:messages";
try {
Redis::publish($channel, $message->message_id);
//todo::优化这里。
Redis::publish($channel, json_encode($message->toArray(), JSON_UNESCAPED_UNICODE|JSON_INVALID_UTF8_IGNORE));
} catch (\Throwable $e) {
logger()->warning('Redis publish failed', [
'session_id' => $message->session_id,

View File

@@ -44,7 +44,7 @@ class OutputSink
'delta_index' => $deltaIndex,
]),
'dedupe_key' => $dedupeKey,
]);
],$wasDupe,false);
}
/**