Google Cloud Spanner 儲存空間
Google Cloud Spanner 儲存空間實作為 Mastra 提供可水平擴充容量、具備強一致性的儲存 backend。它以 Cloud Spanner 的 GoogleSQL dialect 為目標。
安裝「安裝」的直接連結
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/spanner@latest
pnpm add @mastra/spanner@latest
yarn add @mastra/spanner@latest
bun add @mastra/spanner@latest
使用方式「使用方式」的直接連結
import { SpannerStore } from '@mastra/spanner'
const storage = new SpannerStore({
id: 'spanner-storage',
projectId: process.env.SPANNER_PROJECT_ID!,
instanceId: process.env.SPANNER_INSTANCE_ID!,
databaseId: process.env.SPANNER_DATABASE_ID!,
})
執行個體與資料庫必須已存在。Adapter 會在首次使用時建立所需資料表,因此提供給 Spanner client 的 credential 需要執行 schema 變更的權限(或在部署步驟中使用較高權限的 credential 執行一次 storage.init())。
參數「參數」的直接連結
id:
projectId?:
database,否則為必填。instanceId?:
database,否則為必填。databaseId?:
database,否則為必填。database?:
spannerOptions?:
@google-cloud/spanner client 建構函式的選項。可用來設定 credential、自訂 endpoint,或指向本機 emulator。disableInit?:
storage.init()。skipDefaultIndexes?:
indexes?:
initMode?:
'sync' 會在 init() 期間建立缺少的資料表、欄位與索引(既有行為)。'validate' 不會發出 DDL,而是確認每個預期的資料表、欄位與預設/自訂索引都已存在;若有任何缺漏,就擲回有型別的使用者錯誤。當外部處理程序(Terraform、Liquibase、release pipeline 等)擁有 schema,而 Mastra 只應進行驗證時,此選項很有用。建構函式範例「建構函式範例」的直接連結
你可以使用多種方式建立 SpannerStore 執行個體:
import { Spanner } from '@google-cloud/spanner'
import { SpannerStore } from '@mastra/spanner'
// Using projectId / instanceId / databaseId
const store1 = new SpannerStore({
id: 'spanner-storage-1',
projectId: 'my-gcp-project',
instanceId: 'my-instance',
databaseId: 'mastra',
})
// Reusing an existing Spanner Database handle
const spanner = new Spanner({ projectId: 'my-gcp-project' })
const database = spanner.instance('my-instance').database('mastra')
const store2 = new SpannerStore({
id: 'spanner-storage-2',
database,
})
// Using the local Spanner emulator (set the SPANNER_EMULATOR_HOST env var)
process.env.SPANNER_EMULATOR_HOST = 'localhost:9010'
const store3 = new SpannerStore({
id: 'spanner-storage-emulator',
projectId: 'test-project',
instanceId: 'test-instance',
databaseId: 'test-db',
spannerOptions: { servicePath: 'localhost', port: 9010, sslCreds: undefined },
})
其他注意事項「其他注意事項」的直接連結
Schema 管理「Schema 管理」的直接連結
儲存 adapter 會建立下列資料表,全部使用 GoogleSQL dialect:
mastra_workflow_snapshot:Workflow 狀態與執行資料mastra_threads:對話 threadmastra_messages:個別訊息mastra_resources:資源 working memorymastra_scorers:評估分數mastra_background_tasks:背景 Tool 執行狀態mastra_agents:精簡 Agent 記錄(id、狀態、作用中版本)mastra_agent_versions:版本化 Agent 設定 snapshotmastra_mcp_clients/mastra_mcp_client_versions:MCP client 設定及其版本歷程mastra_mcp_servers/mastra_mcp_server_versions:MCP server 設定及其版本歷程mastra_skills/mastra_skill_versions:Skill 記錄與版本化 Skill snapshot(指示、參考資料、script、asset、內容樹)mastra_skill_blobs:以 SHA-256 hash 作為 key 的 content-addressable blob store,用於 Skill 版本內容mastra_prompt_blocks/mastra_prompt_block_versions:prompt block 記錄與版本化內容 snapshot(範本內容、規則、request-context schema)mastra_scorer_definitions/mastra_scorer_definition_versions:scorer 定義記錄與版本化設定 snapshot(judge 指示、model、分數範圍、預設設定、預設 sampling)mastra_schedules/mastra_schedule_triggers:由 cron 驅動的 Workflow 排程與觸發歷程,供 Mastra 內建WorkflowScheduler使用mastra_workspaces/mastra_workspace_versions:Workspace 記錄與版本化設定 snapshot(檔案系統、Sandbox、mount、搜尋、Skill、Tool)mastra_datasets/mastra_dataset_items/mastra_dataset_versions:評估 dataset、SCD-2 版本化項目與版本 snapshotmastra_experiments/mastra_experiment_results:實驗執行及其各項目結果mastra_favorites:各使用者的 Agent 與 Skill 收藏項目,並在 parent 記錄上維護 denormalizedfavoriteCountmastra_channel_installations/mastra_channel_config:多平台 channel installation 與各平台設定mastra_ai_spans:用於可觀測性的 AI tracing span(各 Trace 與各 span 記錄,用來支援 Studio Trace UI)
建立資料表時,文字與 JSON payload 使用 STRING(MAX),另使用 INT64、FLOAT64、BOOL 與 TIMESTAMP。
下列資料表具有 Spanner 專用的 STORED generated column,adapter 會從 JSON payload 填入內容,讓常見 filter 可使用一般 secondary index,不必進行 JSON_VALUE scan:
mastra_workflow_snapshot.snapshotStatus:從snapshot擷取$.status。支援listWorkflowRuns({ status })。mastra_schedules.target_workflow_id:從target擷取$.workflowId。支援listSchedules({ workflowId })。
兩者都會在 init() 期間透過 ALTER TABLE ... ADD COLUMN IF NOT EXISTS 新增,並在 initMode: 'validate'(schema 由外部擁有)時略過。欄位不存在時,adapter 會在 runtime fallback 至 JSON_VALUE filter。
Adapter 不會建立或使用 schema。請使用專用資料庫進行隔離。
初始化「初始化」的直接連結
將 storage 傳入 Mastra 類別時,系統會在任何 storage 操作之前自動呼叫 init():
import { Mastra } from '@mastra/core'
import { SpannerStore } from '@mastra/spanner'
const storage = new SpannerStore({
id: 'spanner-storage',
projectId: process.env.SPANNER_PROJECT_ID!,
instanceId: process.env.SPANNER_INSTANCE_ID!,
databaseId: process.env.SPANNER_DATABASE_ID!,
})
const mastra = new Mastra({
storage, // init() is called automatically
})
若直接使用 storage,請在第一次操作前呼叫一次 init()。Spanner 不允許並行 schema 變更,因此 SpannerStore.init() 會依序執行各 domain 的設定。
const storage = new SpannerStore({
id: 'spanner-storage',
projectId: process.env.SPANNER_PROJECT_ID!,
instanceId: process.env.SPANNER_INSTANCE_ID!,
databaseId: process.env.SPANNER_DATABASE_ID!,
})
await storage.init()
const memory = await storage.getStore('memory')
const thread = await memory?.getThreadById({ threadId: '...' })
若未呼叫 init() 且 disableInit 為 true,所需資料表不會存在,儲存操作也會失敗。
GoogleSQL 特性「GoogleSQL 特性」的直接連結
部分行為與其他關聯式 adapter 不同:
- Upsert 使用
INSERT OR UPDATE。Spanner 不為 upsert 提供RETURNINGclause,因此需要寫入後狀態的呼叫端必須重新讀取。 - 沒有
TRUNCATE。dangerouslyClearAll()會發出DELETE WHERE TRUE。 - 識別碼使用反引號括住。
- DDL 透過
database.updateSchema(...)套用,這是非同步操作(長時間執行的操作)。 - 不支援
NULLS FIRST/LAST。使用IS NULL排序 key 模擬包含 NULL 處理的排序。 - 不原生支援 JSON containment。
listTraces的metadata與scopefilter 會編譯為各 key 的JSON_VALUE(...) = @v相等檢查,而tagsfilter 則編譯為對JSON_QUERY_ARRAY(...)使用EXISTS。這與 Postgres 的@>containment operator 不同(後者可在單次 index scan 中比對巢狀結構):大多數單次查詢仍可運作,但無法表達深層巢狀結構比對。
直接存取資料庫「直接存取資料庫」的直接連結
SpannerStore 會提供底層 Spanner client 物件:
store.database // @google-cloud/spanner Database
store.instance // @google-cloud/spanner Instance (when created internally)
store.spanner // @google-cloud/spanner Spanner client (when created internally)
這些項目適用於自訂交易或 schema introspection 等進階情境。直接重複使用資料庫時,會略過 adapter 的驗證與 JSON 轉換邏輯。
使用 emulator 進行本機開發「使用 emulator 進行本機開發」的直接連結
使用 Docker 在本機執行 Cloud Spanner emulator:
docker run -p 9010:9010 -p 9020:9020 gcr.io/cloud-spanner-emulator/emulator
請設定 SPANNER_EMULATOR_HOST=localhost:9010,並在執行應用程式前建立執行個體與資料庫:
gcloud spanner instances create test-instance --config=emulator-config --nodes=1
gcloud spanner databases create test-db --instance=test-instance
接著在 Node.js 處理程序中設定相同環境變數並連線。@google-cloud/spanner client 會自動偵測 emulator。