系统架构
IndexFlow 是一个高吞吐、编译型 Rust 服务。它将异步 Web 服务器、启用预写式日志(WAL)的嵌入式 SQLite 数据库、后台 worker,以及独立的技术 SEO 和 sitemap 库组合为一个可部署的二进制文件。
1. 高层架构分层
┌─────────────────────────────────────────────────────────────────────────┐
│ 1. Presentation Layer │
│ - Axum 0.7 HTTP Router │
│ - Interactive Web Console (Askama HTML Templates + HTMX) │
│ - JSON REST & API Endpoints (/api/v1/*) │
└────────────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 2. Application Layer │
│ - PipelineManager (Arc<RwLock<HashSet<PipelineStage>>>) │
│ - SiteService - UrlService - SitemapService │
│ - HealthService - GscService - BingService │
│ - SubmissionService - ViewBoostRegistry │
└────────────┬───────────────────────────────────────────────┬────────────┘
│ │
▼ ▼
┌──────────────────────────┐ ┌────────────────────────┐
│ 3. Background Workers │ │ 4. Standalone Crates │
│ - SyncWorker │ │ - indexflow-sitemap │
│ - SeoAuditWorker (x30) │ │ - indexflow-seo │
│ - GscInspectWorker (x3) │ └────────────────────────┘
│ - BingInspectWorker(x2) │ │
│ - BingSubmitWorker │ ┌────────────┴───────────┐
│ - GoogleSubmitWorker │ │ 5. External Providers │
└────────────┬─────────────┘ │ - Google OAuth2 / GSC │
│ │ - Bing IndexNow / BWT │
▼ └────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ 6. Infrastructure & Storage │
│ - SQLite 3 (WAL Mode, synchronous = NORMAL, busy_timeout = 5s) │
│ - Repositories: UrlRepo, SiteRepo, AdminRepo, HealthCheckRepo, │
│ SubmissionLogRepo, IndexHistoryRepo │
└─────────────────────────────────────────────────────────────────────────┘
2. 流水线生命周期与并发管理
IndexFlow 使用线程安全的 PipelineManager 协调后台工作流。引擎不使用分散的原子标志,而是维护正在运行阶段的活动集合:
pub enum PipelineStage {
Sitemap, // Stage 1: Sitemap asset discovery
SeoGate, // Stage 2: Technical SEO & GEO pre-flight audit
GscInspect, // Stage 3a: Google Search Console inspection & pool sync
BingInspect, // Stage 3b: Bing Webmaster Tools official inspection
PushSubmit, // Stage 4: Engine active push (IndexNow & Google Indexing)
}
阶段转换与并发预算
[ Trigger: UI or API ]
│
▼
[ PipelineManager::start(stage) ]
│
├───> SyncWorker (1 Task per Site, chunks of 500 records)
├───> SeoAuditWorker (Concurrency: 30 Semaphore, 5MB body cap)
├───> GscInspectWorker (Concurrency: 3, 250ms interval, 429 auto-stop)
├───> BingInspectWorker (Concurrency: 2, 500ms interval, 1.5 QPS throttle backoff)
└───> PushWorkers (Google: Rolling 24h quota; Bing: Batch JSON)
▼
[ Queue Exhausted -> PipelineManager::stop(stage) ]
3. URL 优先级调度算法
URL 从 sitemap 发现或同步时,IndexFlow 会计算 1 到 999 的调度优先级整数(数值越小表示紧急程度越高)。这直接决定所有后台检查和审计 worker 使用的 ORDER BY priority ASC, id ASC 领取顺序。
分数通过 compute_url_priority 计算:
$$\text{Priority} = \text{Score}{\text{sitemap}} + \text{Score}{\text{age}} + \text{Penalty}{\text{known}} + \text{Boost}{\text{update}}$$
pub fn compute_url_priority(
sitemap_priority: Option<f64>,
lastmod: Option<DateTime<Utc>>,
previous_lastmod: Option<DateTime<Utc>>,
is_new: bool,
now: DateTime<Utc>,
) -> i32 {
let sp = sitemap_priority.unwrap_or(0.5).clamp(0.0, 1.0);
let from_sitemap = ((1.0 - sp) * 400.0).round() as i32;
let from_lastmod = match lastmod { None => 150, Some(lm) => { let age = now.signed_duration_since(lm); if age <= Duration::hours(24) { 0 } else if age <= Duration::days(7) { 40 } else if age <= Duration::days(30) { 100 } else if age <= Duration::days(90) { 180 } else { 280 } } };
let from_new = if is_new { 0 } else { 80 };
let from_update = match (lastmod, previous_lastmod) { (Some(cur), Some(prev)) if cur > prev => -60, (Some(_), None) if !is_new => -30, _ => 0, };
(from_sitemap + from_lastmod + from_new + from_update).clamp(1, 999)
}
4. 查看加速机制
操作员在 Web 控制台(/indexing 或 /seo)查看 URL 的具体页面时,当前可见 URL 应优先接受检查。
IndexFlow 实现了 View Boost Registry(ViewBoostRegistry):
- 渲染分页表格视图时,处理器登记可见 URL ID:
state.view_boost.record(current_site_id, items.iter().map(|u| u.id).collect()); - worker 查询以 30 秒 TTL 优先获取这些活动 ID:
SELECT * FROM urls WHERE gsc_index_status = 'UNKNOWN' ORDER BY (CASE WHEN id IN ($1, $2, $3...) THEN 0 ELSE 1 END), priority ASC, id ASC LIMIT 50; - 这样后台处理大型队列时,UI 仍能获得实时响应。
5. Token 缓存与提供商认证
Google OAuth2 架构
Google API 要求使用 RSA-SHA256 签名的 JWT assertion 交换访问 token。
GoogleAuthClient解析服务账号 JSON 密钥。- 使用
webmasters.readonly和indexingscope 签署有效期 1 小时的 JWT。 - 将交换得到的 OAuth2 Bearer token 缓存在内存
RwLock<HashMap<String, CachedToken>>中。 - 剩余有效期少于 5 分钟时自动刷新,避免重复网络往返。
Bing Webmaster Tools API 缓存
Bing 通过查询参数(?apikey=...)传递 API 密钥。
BingProvider通过GetUserSites解析规范站点身份前缀。- 按站点在内存中缓存解析出的资源 URL,减少外部 API 调用。