11using System ;
22using System . Collections . Generic ;
3+ using System . Diagnostics ;
34using System . Linq ;
45using System . Security . Cryptography ;
56using System . Text ;
@@ -584,6 +585,12 @@ public async Task BuildCompletedAsync(string sfProjectId, string buildId, string
584585 {
585586 try
586587 {
588+ string ? draftGenerationRequestId = await GetDraftGenerationRequestIdForBuildAsync ( buildId ) ;
589+ if ( ! string . IsNullOrEmpty ( draftGenerationRequestId ) )
590+ {
591+ Activity . Current ? . AddTag ( "draftGenerationRequestId" , draftGenerationRequestId ) ;
592+ }
593+
587594 // Retrieve the build started from the event metric. We do this as there may be multiple builds started,
588595 // and this ensures that only builds that want to send an email will have one sent.
589596 var eventMetrics = await eventMetricService . GetEventMetricsAsync (
@@ -680,8 +687,15 @@ await projectSecrets.UpdateAsync(
680687 cancellationToken
681688 ) ;
682689
690+ string buildId = translationBuild . Id ;
691+ string ? draftGenerationRequestId = await GetDraftGenerationRequestIdForBuildAsync ( buildId ) ;
692+ if ( ! string . IsNullOrEmpty ( draftGenerationRequestId ) )
693+ {
694+ Activity . Current ? . AddTag ( "draftGenerationRequestId" , draftGenerationRequestId ) ;
695+ }
696+
683697 // Return the build id so it can be logged
684- return translationBuild . Id ;
698+ return buildId ;
685699 }
686700 catch ( ServalApiException e ) when ( e . StatusCode == StatusCodes . Status404NotFound )
687701 {
@@ -765,6 +779,13 @@ public async Task ExecuteWebhookAsync(string json, string signature)
765779 return ;
766780 }
767781
782+ // Add the draftGenerationRequestId to associate with other events.
783+ string ? draftGenerationRequestId = await GetDraftGenerationRequestIdForBuildAsync ( buildId ) ;
784+ if ( ! string . IsNullOrEmpty ( draftGenerationRequestId ) )
785+ {
786+ Activity . Current ? . AddTag ( "draftGenerationRequestId" , draftGenerationRequestId ) ;
787+ }
788+
768789 // Record that the webhook was run successfully
769790 var arguments = new Dictionary < string , object >
770791 {
@@ -1800,17 +1821,23 @@ await projectSecrets.UpdateAsync(
18001821 ) ;
18011822
18021823 // Notify any SignalR clients subscribed to the project
1824+ string ? buildId = translationBuild ? . Id ;
18031825 await hubContext . NotifyBuildProgress (
18041826 sfProjectId ,
1805- new ServalBuildState
1827+ new ServalBuildState { BuildId = buildId , State = nameof ( ServalData . PreTranslationsRetrieved ) }
1828+ ) ;
1829+
1830+ if ( ! string . IsNullOrEmpty ( buildId ) )
1831+ {
1832+ string ? draftGenerationRequestId = await GetDraftGenerationRequestIdForBuildAsync ( buildId ) ;
1833+ if ( ! string . IsNullOrEmpty ( draftGenerationRequestId ) )
18061834 {
1807- BuildId = translationBuild ? . Id ,
1808- State = nameof ( ServalData . PreTranslationsRetrieved ) ,
1835+ Activity . Current ? . AddTag ( "draftGenerationRequestId" , draftGenerationRequestId ) ;
18091836 }
1810- ) ;
1837+ }
18111838
18121839 // Return the build id
1813- return translationBuild ? . Id ;
1840+ return buildId ;
18141841 }
18151842 }
18161843 catch ( TaskCanceledException e ) when ( e . InnerException is not TimeoutException )
@@ -1879,6 +1906,7 @@ public async Task StartBuildAsync(string curUserId, string sfProjectId, Cancella
18791906 curUserId ,
18801907 new BuildConfig { ProjectId = sfProjectId } ,
18811908 false ,
1909+ null ,
18821910 CancellationToken . None
18831911 ) ,
18841912 null ,
@@ -1904,6 +1932,8 @@ public async Task StartPreTranslationBuildAsync(
19041932 CancellationToken cancellationToken
19051933 )
19061934 {
1935+ string draftGenerationRequestId = ObjectId . GenerateNewId ( ) . ToString ( ) ;
1936+ Activity . Current ? . AddTag ( "draftGenerationRequestId" , draftGenerationRequestId ) ;
19071937 // Load the project from the realtime service
19081938 await using IConnection conn = await realtimeService . ConnectAsync ( curUserId ) ;
19091939 IDocument < SFProject > projectDoc = await conn . FetchAsync < SFProject > ( buildConfig . ProjectId ) ;
@@ -2018,7 +2048,14 @@ await projectDoc.SubmitJson0OpAsync(op =>
20182048 // so that the interceptor functions for BuildProjectAsync().
20192049 jobId = backgroundJobClient . ContinueJobWith < MachineProjectService > (
20202050 jobId ,
2021- r => r . BuildProjectForBackgroundJobAsync ( curUserId , buildConfig , true , CancellationToken . None )
2051+ r =>
2052+ r . BuildProjectForBackgroundJobAsync (
2053+ curUserId ,
2054+ buildConfig ,
2055+ true ,
2056+ draftGenerationRequestId ,
2057+ CancellationToken . None
2058+ )
20222059 ) ;
20232060
20242061 // Set the pre-translation queued date and time, and hang fire job id
@@ -2586,6 +2623,29 @@ CancellationToken cancellationToken
25862623 return project ;
25872624 }
25882625
2626+ /// <summary>
2627+ /// Gets the SF-specific draft generation request identifier for a build by looking up the BuildProjectAsync event.
2628+ /// </summary>
2629+ /// <param name="buildId">The Serval build identifier.</param>
2630+ /// <returns>The draft generation request identifier, or null if not found.</returns>
2631+ private async Task < string ? > GetDraftGenerationRequestIdForBuildAsync ( string buildId )
2632+ {
2633+ // BuildProjectAsync events serve as a record of what Serval build id corresponds to what draft generation
2634+ // request id.
2635+ const int lookupTimeframeDays = 60 ;
2636+ DateTime startDate = DateTime . UtcNow . AddDays ( - lookupTimeframeDays ) ;
2637+ QueryResults < EventMetric > buildProjectEvents = await eventMetricService . GetEventMetricsAsync (
2638+ projectId : null ,
2639+ scopes : [ EventScope . Drafting ] ,
2640+ eventTypes : [ nameof ( MachineProjectService . BuildProjectAsync ) ] ,
2641+ fromDate : startDate
2642+ ) ;
2643+ EventMetric ? buildEvent = buildProjectEvents . Results . FirstOrDefault ( e => e . Result ? . ToString ( ) == buildId ) ;
2644+ return ( buildEvent ? . Tags ? . TryGetValue ( "draftGenerationRequestId" , out BsonValue ? requestId ) == true )
2645+ ? requestId ? . AsString
2646+ : null ;
2647+ }
2648+
25892649 private async Task < string > GetTranslationIdAsync (
25902650 string sfProjectId ,
25912651 bool preTranslate ,
0 commit comments