Skip to content
AI 文档索引 ↗

服务端事件与用户操作 ​

服务端 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
删除 ItemitemDelete(itemType, itemId)提交 Item 删除操作;存储投影由接收端决定$item_delete
缓冲冲刷flush()发起冲刷并返回本次结果,确认情况以有效 ACK 为准网络批次上报
优雅停机close()停止接收新事件并在限时内尝试排空队列;不能保证全部 ACK停机资源清理

一、 服务端身份模型 (Server Identity) ​

每次调用显式提供事件身份;SDK 不保存进程级“当前用户”:

text
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 仅能用于关联,不能作为服务端认证依据。

java
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"));
go
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 与约束 ​

参数字段类型是否必填取值范围 / 约束说明
lifecycleKindstring必填枚举限定:"request"(HTTP/RPC 请求)、"job"(后台定时任务/批处理)、"transaction"(业务事务)
lifecycleNamestring必填低基数操作名(长度 1..128)。严禁传入带高基数主键的原始 URL,推荐使用路由模板(如 /api/v1/orders/{id}/pay)或任务类型名
lifecyclePhasestring必填枚举限定:"started"(阶段开始)、"completed"(正常完成)、"failed"(执行失败)
operationIdstring必填链路关联主键(长度 8..128),同一操作的 started 与 completed/failed 必须共享相同 operationId
durationMsinteger终态必填操作耗时毫秒数(整数 $\ge 0$)。在 completed 或 failed 阶段必填,由宿主显式度量
errorTypestring可选异常分类标识(长度 1..128,仅允许在 failed 阶段出现)。严禁包含堆栈信息或明文 PII
attributesobject可选结构化辅助属性键值对(如重试轮次、状态码等)

2. 各语言调用示例 ​

java
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());
go
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_setprofileSetproperties: object提交用户画像属性更新(如会员等级);字段含义和敏感性由业务定义
$profile_set_onceprofileSetOnceproperties: object请求仅在目标属性不存在时写入;执行结果由接收端决定
$profile_incrementprofileIncrementproperties: map<string, finite number>请求接收端执行数值增减;并发原子性由部署实现负责(如积分 +100)
$profile_appendprofileAppendproperties: map<string, array>每个数组最多 100 项,元素限同类型字符串或数值;合同不规定接收端去重策略
$profile_unsetprofileUnset / profileClearkeys: string[]请求移除指定的用户画像属性键名;键列表最多 100 项
$profile_deleteprofileDelete无参数仅当部署端实现该操作时执行;不等于删除历史事件、备份或身份图谱
$item_setitemSetitemType: string, itemId: string, properties: object提交指定 Item 的属性变更;数据投影和存储位置由部署端定义
$item_deleteitemDeleteitemType: string, itemId: string提交指定 Item 的删除操作;数据投影由部署端定义

profileClear 便利方法保留,当前与 profileUnset 一样产生有界 $profile_unset,空键列表不产生成功入队记录。


四、 服务端预置上下文与属性分层 ​

1. 服务端合法预置上下文 (context.*) ​

在构造服务端客户端时,宿主可通过 defaultContext 注入服务运行环境。服务端仅允许以下 5 大白名单字段:

字段名称类型长度约束业务含义与示例
context.servicestring1..128当前微服务/应用标识,例如 "order-service"、"payment-gateway"
context.serviceVersionstring1..64服务语义化版本号,例如 "v2.4.1"
context.environmentstring1..32运行环境标识,例如 "production"、"staging"、"test"
context.regionstring1..64机房或可用区标识,例如 "cn-hangzhou-zone-a"、"ap-southeast-1"
context.deploymentstring1..64部署单元或集群名,例如 "k8s-prod-cluster-01"

SDK 不自动读取主机名、IP/MAC、容器 ID 或进程参数。SDK 名称、版本与语言放在事件根级 sdk 中。defaultContext 仅接受上表字段;单次事件可用的 context 字段以对应语言 API 为准。

2. 属性分层与优先级覆盖链 ​

业务属性按以下顺序合并,同名字段由后者覆盖:

text
静态公共属性 → 动态请求属性 → 单次事件属性

defaultContext 单独写入 context.*,不参与 properties 的覆盖。动态属性中的租户业务标签不能代替 ServerIdentity.tenantId 的权威上下文。

  • 动态属性 (Dynamic Properties):适合绑定微服务 trace_id、当前协程的租户 ID。各 SDK 通过语言原生机制实现:
    • Java:Supplier<Map<String, Object>> 读取 ThreadLocal 或 MDC;
    • Go:TrackContext(ctx, ...) 显式首参传递;