11import {
22 DeploymentErrorData ,
33 ExternalBuildData ,
4+ logger ,
45 prepareDeploymentError ,
56} from "@trigger.dev/core/v3" ;
67import { type RuntimeEnvironment , type WorkerDeployment } from "@trigger.dev/database" ;
@@ -13,6 +14,21 @@ import { getUsername } from "~/utils/username";
1314import { processGitMetadata } from "./BranchesPresenter.server" ;
1415import { S2 } from "@s2-dev/streamstore" ;
1516import { env } from "~/env.server" ;
17+ import { createRedisClient } from "~/redis.server" ;
18+ import { tryCatch } from "@trigger.dev/core" ;
19+
20+ const S2_TOKEN_KEY_PREFIX = "s2-token:project:" ;
21+
22+ const s2TokenRedis = createRedisClient ( "s2-token-cache" , {
23+ host : env . CACHE_REDIS_HOST ,
24+ port : env . CACHE_REDIS_PORT ,
25+ username : env . CACHE_REDIS_USERNAME ,
26+ password : env . CACHE_REDIS_PASSWORD ,
27+ tlsDisabled : env . CACHE_REDIS_TLS_DISABLED === "true" ,
28+ clusterMode : env . CACHE_REDIS_CLUSTER_MODE_ENABLED === "1" ,
29+ } ) ;
30+
31+ const s2 = env . S2_ENABLED === "1" ? new S2 ( { accessToken : env . S2_ACCESS_TOKEN } ) : undefined ;
1632
1733export type ErrorData = {
1834 name : string ;
@@ -149,26 +165,17 @@ export class DeploymentPresenter {
149165
150166 let s2Logs = undefined ;
151167 if ( env . S2_ENABLED === "1" && gitMetadata ?. source === "trigger_github_app" ) {
152- const s2 = new S2 ( { accessToken : env . S2_ACCESS_TOKEN } ) ;
153- const projectS2AccessToken = await s2 . accessTokens . issue ( {
154- id : `${ project . externalRef } -${ new Date ( ) . getTime ( ) } ` ,
155- expires_at : new Date ( Date . now ( ) + 60 * 60 * 1000 ) . toISOString ( ) , // 1 hour
156- scope : {
157- ops : [ "read" ] ,
158- basins : {
159- exact : env . S2_DEPLOYMENT_LOGS_BASIN_NAME ,
160- } ,
161- streams : {
162- prefix : `projects/${ project . externalRef } /deployments/` ,
163- } ,
164- } ,
165- } ) ;
168+ const [ error , accessToken ] = await tryCatch ( this . getS2AccessToken ( project . externalRef ) ) ;
166169
167- s2Logs = {
168- basin : env . S2_DEPLOYMENT_LOGS_BASIN_NAME ,
169- stream : `projects/${ project . externalRef } /deployments/${ deployment . shortCode } ` ,
170- accessToken : projectS2AccessToken . access_token ,
171- } ;
170+ if ( error ) {
171+ logger . error ( "Failed getting S2 access token" , { error } ) ;
172+ } else {
173+ s2Logs = {
174+ basin : env . S2_DEPLOYMENT_LOGS_BASIN_NAME ,
175+ stream : `projects/${ project . externalRef } /deployments/${ deployment . shortCode } ` ,
176+ accessToken,
177+ } ;
178+ }
172179 }
173180
174181 return {
@@ -213,6 +220,41 @@ export class DeploymentPresenter {
213220 } ;
214221 }
215222
223+ private async getS2AccessToken ( projectRef : string ) : Promise < string > {
224+ if ( env . S2_ENABLED !== "1" || ! s2 ) {
225+ throw new Error ( "Failed getting S2 access token: S2 is not enabled" ) ;
226+ }
227+
228+ const redisKey = `${ S2_TOKEN_KEY_PREFIX } ${ projectRef } ` ;
229+ const cachedToken = await s2TokenRedis . get ( redisKey ) ;
230+
231+ if ( cachedToken ) {
232+ return cachedToken ;
233+ }
234+
235+ const { access_token : accessToken } = await s2 . accessTokens . issue ( {
236+ id : `${ projectRef } -${ new Date ( ) . getTime ( ) } ` ,
237+ expires_at : new Date ( Date . now ( ) + 60 * 60 * 1000 ) . toISOString ( ) , // 1 hour
238+ scope : {
239+ ops : [ "read" ] ,
240+ basins : {
241+ exact : env . S2_DEPLOYMENT_LOGS_BASIN_NAME ,
242+ } ,
243+ streams : {
244+ prefix : `projects/${ projectRef } /deployments/` ,
245+ } ,
246+ } ,
247+ } ) ;
248+
249+ await s2TokenRedis . setex (
250+ redisKey ,
251+ 59 * 60 , // slightly shorter than the token validity period
252+ accessToken
253+ ) ;
254+
255+ return accessToken ;
256+ }
257+
216258 public static prepareErrorData ( errorData : WorkerDeployment [ "errorData" ] ) : ErrorData | undefined {
217259 if ( ! errorData ) {
218260 return ;
0 commit comments