服务端事件与用户操作
服务端 SDK 默认使用队列和后台 Worker,不保存进程级当前用户;事件身份由每次调用显式提供。服务端与客户端共用事件接收路径,但使用不同的事件结构,不得混合在同一批次。
本文列出身份、生命周期、画像和对象操作的共同规则。具体方法签名见:
快速调用总览
| 接口分类 | 语义化调用形式 | 核心说明 | 产生事件 / 操作 |
|---|---|---|---|
| 业务事件上报 | track(eventName, identity, properties, options) | 将业务事件提交到配置的队列或发送通道 | 自定义业务事件 |
| 生命周期追踪 | trackLifecycle(lifecycleInput) | 微服务请求、异步任务与事务耗时度量 | $server_lifecycle |
| 注册/登录关联 | trackSignup(userId, anonymousId, properties) | 提交注册/登录关联事件;身份图谱合并由接收端决定 | $identity_login |
| 组织/租户关联 | group(groupId, identity, traits) | 提交带组织标识的关联操作;后续分析语义由接收端决定 | $group |
| 设置画像属性 | profileSet(identity, properties) | 提交画像属性设置操作 | $profile_set |
| 画像首次写入 | profileSetOnce(identity, properties) | 提交仅填充缺失属性的操作 | $profile_set_once |
| 数值画像累加 | profileIncrement(identity, properties) | 提交数值属性增减操作 | $profile_increment |
| 数组画像追加 | profileAppend(identity, properties) | 提交有界字符串或数值数组操作;不保证接收端去重 | $profile_append |
| 移除特定属性 | profileUnset(identity, keys) | 请求移除指定的用户画像属性键名 | $profile_unset |
| 清理指定属性 | profileClear(identity, keys) | 请求清理指定画像属性键;不是清空整个画像 | $profile_unset |
| 删除用户画像 | profileDelete(identity) | 请求删除画像属性记录;是否执行取决于接收端支持 | $profile_delete |
| 设置 Item 属性 | itemSet(itemType, itemId, properties) | 提交 Item 属性操作;存储投影由接收端决定 | $item_set |
| 删除 Item | itemDelete(itemType, itemId) | 提交 Item 删除操作;存储投影由接收端决定 | $item_delete |
| 缓冲冲刷 | flush() | 发起冲刷并返回本次结果,确认情况以有效 ACK 为准 | 网络批次上报 |
| 优雅停机 | close() | 停止接收新事件并在限时内尝试排空队列;不能保证全部 ACK | 停机资源清理 |
一、 服务端身份模型 (Server Identity)
每次调用显式提供事件身份;SDK 不保存进程级“当前用户”:
ServerIdentity {
userId?: string, // 业务认证后的用户标识 (如 "u_10029348")
anonymousId?: string, // 前端透传的匿名标识,仅用于关联
installationId?: string, // 宿主显式提供的安装标识
deviceId?: string, // 宿主显式提供的设备标识
identityBindings?: Map, // 经业务治理批准的多命名空间业务标识 (如 {"loyalty_member_id": "member_..."})
groupId?: string, // B2B 组织/企业主键
tenantId?: string // 宿主认证后的租户上下文
}IMPORTANT
主体身份要求:须提供合法的主体身份字段(如 userId、anonymousId、installationId、deviceId 或受控 identityBindings);groupId/tenantId 单独存在不构成主体身份。trackSignup 须同时提供 userId 与 anonymousId。客户端透传 ID 仅能用于关联,不能作为服务端认证依据。
ServerIdentity identity = ServerIdentity.builder()
.userId("user_1024")
.tenantId("tenant_acme")
.build();
client.track("order_paid", identity,
java.util.Collections.<String, Object>singletonMap("orderId", "ord_99"));identity := server.Identity{
UserID: "user_1024",
TenantID: "tenant_acme",
}
analytics.Track(server.TrackInput{
EventName: "order_paid",
Identity: identity,
Properties: map[string]any{"orderId": "ord_99", "amountCents": 19900},
})二、 服务端生命周期追踪 ($server_lifecycle)
$server_lifecycle 记录服务请求、后台任务或事务的阶段与耗时。
1. 参数 Schema 与约束
| 参数字段 | 类型 | 是否必填 | 取值范围 / 约束说明 |
|---|---|---|---|
lifecycleKind | string | 必填 | 枚举限定:"request"(HTTP/RPC 请求)、"job"(后台定时任务/批处理)、"transaction"(业务事务) |
lifecycleName | string | 必填 | 低基数操作名(长度 1..128)。严禁传入带高基数主键的原始 URL,推荐使用路由模板(如 /api/v1/orders/{id}/pay)或任务类型名 |
lifecyclePhase | string | 必填 | 枚举限定:"started"(阶段开始)、"completed"(正常完成)、"failed"(执行失败) |
operationId | string | 必填 | 链路关联主键(长度 8..128),同一操作的 started 与 completed/failed 必须共享相同 operationId |
durationMs | integer | 终态必填 | 操作耗时毫秒数(整数 $\ge 0$)。在 completed 或 failed 阶段必填,由宿主显式度量 |
errorType | string | 可选 | 异常分类标识(长度 1..128,仅允许在 failed 阶段出现)。严禁包含堆栈信息或明文 PII |
attributes | object | 可选 | 结构化辅助属性键值对(如重试轮次、状态码等) |
2. 各语言调用示例
import com.trackbusiness.server.operations.ServerLifecycleOperation;
import com.trackbusiness.server.operations.ServerOperationOptions;
String opId = java.util.UUID.randomUUID().toString();
long start = System.nanoTime();
ServerOperationOptions options = ServerOperationOptions.builder(identity).build();
client.trackLifecycle(ServerLifecycleOperation.builder(options,
ServerLifecycleOperation.Kind.JOB, "BillingMonthlyReconciliation",
ServerLifecycleOperation.Phase.STARTED, opId).build());
reconcile();
client.trackLifecycle(ServerLifecycleOperation.builder(options,
ServerLifecycleOperation.Kind.JOB, "BillingMonthlyReconciliation",
ServerLifecycleOperation.Phase.COMPLETED, opId)
.durationMs((System.nanoTime() - start) / 1_000_000L).build());opID := uuid.NewString()
start := time.Now()
analytics.TrackLifecycleContext(ctx, server.LifecycleInput{
Options: server.OperationOptions{Identity: identity},
Kind: server.LifecycleTransaction,
Name: "InventoryDeduction",
Phase: server.LifecycleStarted,
OperationID: opID,
})
deductInventory()
durationMs := time.Since(start).Milliseconds()
analytics.TrackLifecycleContext(ctx, server.LifecycleInput{
Options: server.OperationOptions{Identity: identity},
Kind: server.LifecycleTransaction,
Name: "InventoryDeduction",
Phase: server.LifecycleCompleted,
OperationID: opID,
DurationMs: &durationMs,
})三、 用户画像与 Item 操作
服务端 SDK 暴露 7 种画像操作和 2 种 Item 操作。它们是 SDK 的业务操作 API,但仍会编码为带有 $profile_* 或 $item_* eventName 的服务端事件,并与普通事件共用事件准入、存储、上传、整批 ACK 和重试路径。它们不是独立的 API 传输通道或已经部署的画像/Item 数据库能力。
SDK 收到整批 ACK,只能确认 Collector 接受了这个批次;是否完成画像或 Item 投影,取决于部署端实现和验证结果。机器可检查的输入结构见 operations.json 与 profile-operations.schema.json。
| 操作标识符 (Operation) | 公开意图 API | 参数与类型约束 | 业务语义与边界保证 |
|---|---|---|---|
$profile_set | profileSet | properties: object | 提交用户画像属性更新(如会员等级);字段含义和敏感性由业务定义 |
$profile_set_once | profileSetOnce | properties: object | 请求仅在目标属性不存在时写入;执行结果由接收端决定 |
$profile_increment | profileIncrement | properties: map<string, finite number> | 请求接收端执行数值增减;并发原子性由部署实现负责(如积分 +100) |
$profile_append | profileAppend | properties: map<string, array> | 每个数组最多 100 项,元素限同类型字符串或数值;合同不规定接收端去重策略 |
$profile_unset | profileUnset / profileClear | keys: string[] | 请求移除指定的用户画像属性键名;键列表最多 100 项 |
$profile_delete | profileDelete | 无参数 | 仅当部署端实现该操作时执行;不等于删除历史事件、备份或身份图谱 |
$item_set | itemSet | itemType: string, itemId: string, properties: object | 提交指定 Item 的属性变更;数据投影和存储位置由部署端定义 |
$item_delete | itemDelete | itemType: string, itemId: string | 提交指定 Item 的删除操作;数据投影由部署端定义 |
profileClear 便利方法保留,当前与 profileUnset 一样产生有界 $profile_unset,空键列表不产生成功入队记录。
四、 服务端预置上下文与属性分层
1. 服务端合法预置上下文 (context.*)
在构造服务端客户端时,宿主可通过 defaultContext 注入服务运行环境。服务端仅允许以下 5 大白名单字段:
| 字段名称 | 类型 | 长度约束 | 业务含义与示例 |
|---|---|---|---|
context.service | string | 1..128 | 当前微服务/应用标识,例如 "order-service"、"payment-gateway" |
context.serviceVersion | string | 1..64 | 服务语义化版本号,例如 "v2.4.1" |
context.environment | string | 1..32 | 运行环境标识,例如 "production"、"staging"、"test" |
context.region | string | 1..64 | 机房或可用区标识,例如 "cn-hangzhou-zone-a"、"ap-southeast-1" |
context.deployment | string | 1..64 | 部署单元或集群名,例如 "k8s-prod-cluster-01" |
SDK 不自动读取主机名、IP/MAC、容器 ID 或进程参数。SDK 名称、版本与语言放在事件根级 sdk 中。defaultContext 仅接受上表字段;单次事件可用的 context 字段以对应语言 API 为准。
2. 属性分层与优先级覆盖链
业务属性按以下顺序合并,同名字段由后者覆盖:
静态公共属性 → 动态请求属性 → 单次事件属性defaultContext 单独写入 context.*,不参与 properties 的覆盖。动态属性中的租户业务标签不能代替 ServerIdentity.tenantId 的权威上下文。
- 动态属性 (Dynamic Properties):适合绑定微服务
trace_id、当前协程的租户 ID。各 SDK 通过语言原生机制实现:- Java:
Supplier<Map<String, Object>>读取ThreadLocal或 MDC; - Go:
TrackContext(ctx, ...)显式首参传递;
- Java: