- 应用骨架: Solon + MyBatis-Plus + PostgreSQL + Redis + Sa-Token - 核心链路: 回调网关 → 消息落库(幂等) → 分发队列(FOR UPDATE SKIP LOCKED) → worker消费/重试/死信 - 多租户隔离: 前缀法账号映射, 所有业务表带 tenant_id - 管理后台: FreeMarker 渲染, 租户/授权/队列/用量管理页面 - 历史消息补拉: 水位线驱动, getRoamMsg/getGroupMsg 增量拉取, 兜底回调丢失 - msg_key 统一算法(回调/补拉共享, 跨路径去重) Co-Authored-By: Claude <noreply@anthropic.com>
53 lines
1.8 KiB
Plaintext
53 lines
1.8 KiB
Plaintext
<#import "_macros.ftl" as m>
|
|
<@m.layout active="queue" title="队列监控">
|
|
<#if msg?has_content>
|
|
<div class="alert">${msg}</div>
|
|
</#if>
|
|
|
|
<h3 style="margin-bottom:10px;font-size:15px;color:#2c3e50">待分发 (pending,最近 50 条)</h3>
|
|
<#if pendings?has_content>
|
|
<table class="data-table">
|
|
<thead><tr><th>ID</th><th>租户</th><th>会话</th><th>重试次数</th><th>下次重试时间</th></tr></thead>
|
|
<tbody>
|
|
<#list pendings as q>
|
|
<tr>
|
|
<td>${q.id?c}</td>
|
|
<td>${q.tenantId!}</td>
|
|
<td>${q.convId!}</td>
|
|
<td>${q.retryCount!0}</td>
|
|
<td><#if q.nextRetryAt??>${q.nextRetryAt?string('yyyy-MM-dd HH:mm:ss')}<#else>-</#if></td>
|
|
</tr>
|
|
</#list>
|
|
</tbody>
|
|
</table>
|
|
<#else>
|
|
<div class="empty">无待分发记录</div>
|
|
</#if>
|
|
|
|
<h3 style="margin:24px 0 10px;font-size:15px;color:#2c3e50">死信 (dead,共 ${deadCount!'0'} 条,最近 50 条)</h3>
|
|
<#if deads?has_content>
|
|
<table class="data-table">
|
|
<thead><tr><th>ID</th><th>租户</th><th>会话</th><th>重试次数</th><th>目标URL</th><th>操作</th></tr></thead>
|
|
<tbody>
|
|
<#list deads as q>
|
|
<tr>
|
|
<td>${q.id?c}</td>
|
|
<td>${q.tenantId!}</td>
|
|
<td>${q.convId!}</td>
|
|
<td>${q.retryCount!0}</td>
|
|
<td class="muted">${q.targetUrl!}</td>
|
|
<td>
|
|
<form method="post" action="${basePath}/admin/queue/redeliver" style="display:inline">
|
|
<input type="hidden" name="id" value="${q.id?c}">
|
|
<button class="btn btn-sm btn-primary">重发</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
</#list>
|
|
</tbody>
|
|
</table>
|
|
<#else>
|
|
<div class="empty">无死信</div>
|
|
</#if>
|
|
</@m.layout>
|