/
Alex_Ural
/
opencode
Обзор
Документация
Войти
/
Alex_Ural
/
opencode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
packages/stats/core/src/athena.ts
151 строка
5 KB
opencode-agent[bot]
chore: generate
10 июл 2026, 03:55
10 июл 2026, 03:55
d09d561
Код
Авторство
О чём код?
import { AthenaClient as AwsAthenaClient, GetQueryExecutionCommand, GetQueryResultsCommand, StartQueryExecutionCommand, type Row, } from "@aws-sdk/client-athena" import { Effect, Layer } from "effect" import * as Context from "effect/Context" import { Resource } from "sst/resource" const ATHENA_MAX_POLL_ATTEMPTS = 300 const ATHENA_PAGE_SIZE = 1000 export type AthenaData = Record<string, string> export class AthenaQueryError extends Error { readonly _tag = "AthenaQueryError" readonly queryExecutionId?: string constructor(input: { message: string; queryExecutionId?: string; cause?: unknown }) { super(input.message, { cause: input.cause }) this.name = "AthenaQueryError" this.queryExecutionId = input.queryExecutionId } } export class AthenaQueryTimeoutError extends Error { readonly _tag = "AthenaQueryTimeoutError" readonly queryExecutionId: string constructor(input: { message: string; queryExecutionId: string }) { super(input.message) this.name = "AthenaQueryTimeoutError" this.queryExecutionId = input.queryExecutionId } } export declare namespace Athena { export interface Service { readonly query: (query: string) => Effect.Effect<AthenaData[], AthenaQueryError | AthenaQueryTimeoutError> } } export class Athena extends Context.Service<Athena, Athena.Service>()("@opencode/stats/Athena") { static readonly layer: Layer.Layer<Athena> = Layer.effect( Athena, Effect.sync(() => { const client = new AwsAthenaClient({ region: Resource.InferenceEvent.region }) const query = Effect.fn("Athena.query")(function* (query: string) { const started = yield* Effect.tryPromise({ try: () => client.send( new StartQueryExecutionCommand({ QueryString: query, WorkGroup: Resource.InferenceEvent.workgroup, QueryExecutionContext: { Catalog: Resource.InferenceEvent.catalog, Database: Resource.InferenceEvent.database, }, }), ), catch: (cause) => new AthenaQueryError({ message: "Failed to start Athena stats query", cause }), }) const queryExecutionId = started.QueryExecutionId if (!queryExecutionId) return yield* Effect.fail(new AthenaQueryError({ message: "Athena did not return a query execution id" })) yield* poll(client, queryExecutionId) return yield* results(client, queryExecutionId) }) return Athena.of({ query }) }), ) } const poll: ( client: AwsAthenaClient, queryExecutionId: string, attempt?: number, ) => Effect.Effect<void, AthenaQueryError | AthenaQueryTimeoutError> = Effect.fn("Athena.poll")(function* ( client: AwsAthenaClient, queryExecutionId: string, attempt = 0, ) { if (attempt > 0) yield* Effect.sleep("2 seconds") const result = yield* Effect.tryPromise({ try: () => client.send(new GetQueryExecutionCommand({ QueryExecutionId: queryExecutionId })), catch: (cause) => new AthenaQueryError({ message: "Failed to poll Athena stats query", queryExecutionId, cause }), }) const status = result.QueryExecution?.Status if (status?.State === "SUCCEEDED") return if (status?.State === "FAILED" || status?.State === "CANCELLED") return yield* Effect.fail( new AthenaQueryError({ message: `Athena stats query ${status.State.toLowerCase()}: ${status.StateChangeReason ?? "unknown reason"}`, queryExecutionId, }), ) if (attempt >= ATHENA_MAX_POLL_ATTEMPTS - 1) return yield* Effect.fail( new AthenaQueryTimeoutError({ message: `Athena stats query ${queryExecutionId} did not complete`, queryExecutionId, }), ) return yield* poll(client, queryExecutionId, attempt + 1) }) const results: (client: AwsAthenaClient, queryExecutionId: string) => Effect.Effect<AthenaData[], AthenaQueryError> = Effect.fn("Athena.results")(function* (client: AwsAthenaClient, queryExecutionId: string) { // Accumulate pages iteratively; recursive spreads copied every previously // fetched row per page and blew up memory on large result sets. const rows: AthenaData[] = [] let nextToken: string | undefined while (true) { const result = yield* Effect.tryPromise({ try: () => client.send( new GetQueryResultsCommand({ QueryExecutionId: queryExecutionId, NextToken: nextToken, MaxResults: ATHENA_PAGE_SIZE, }), ), catch: (cause) => new AthenaQueryError({ message: "Failed to read Athena stats results", queryExecutionId, cause }), }) const columns = result.ResultSet?.ResultSetMetadata?.ColumnInfo?.map((item) => item.Name ?? "") ?? [] // The first page starts with the header row. for (const row of (result.ResultSet?.Rows ?? []).slice(nextToken ? 0 : 1)) rows.push(rowData(columns, row)) if (!result.NextToken) return rows nextToken = result.NextToken } }) function rowData(columns: string[], row: Row): AthenaData { return Object.fromEntries( columns.flatMap((column, index) => { const value = row.Data?.[index]?.VarCharValue if (!column || value === undefined) return [] return [[column, value]] }), ) }