@@ -52,7 +52,7 @@ public ValidationOutcomeProcessor(
5252 _validationConfigurationsByName = _validationConfiguration . Validations . ToDictionary ( v => v . Name ) ;
5353 }
5454
55- public async Task ProcessValidationOutcomeAsync ( PackageValidationSet validationSet , Package package )
55+ public async Task ProcessValidationOutcomeAsync ( PackageValidationSet validationSet , Package package , ValidationSetProcessorResult currentCallStats )
5656 {
5757 var failedValidations = GetFailedValidations ( validationSet ) ;
5858
@@ -102,9 +102,10 @@ public async Task ProcessValidationOutcomeAsync(PackageValidationSet validationS
102102 validationSet . ValidationTrackingId ) ;
103103 }
104104
105- await CompleteValidationSetAsync ( package , validationSet , isSuccess : false ) ;
105+ await CleanupValidationStorageAsync ( validationSet ) ;
106+ TrackValidationSetCompletion ( package , validationSet , isSuccess : false ) ;
106107 }
107- else if ( AllValidationsSucceeded ( validationSet ) )
108+ else if ( AllRequiredValidationsSucceeded ( validationSet ) )
108109 {
109110 _logger . LogInformation ( "All validations are complete for the package {PackageId} {PackageVersion}, validation set {ValidationSetId}" ,
110111 package . PackageRegistration . Id ,
@@ -126,75 +127,28 @@ public async Task ProcessValidationOutcomeAsync(PackageValidationSet validationS
126127 _messageService . SendPackagePublishedMessage ( package ) ;
127128 }
128129
129- await CompleteValidationSetAsync ( package , validationSet , isSuccess : true ) ;
130- }
131- else
132- {
133- // There are no failed validations and some validations are still in progress. Update
134- // the validation set's Updated field and send a notice if the validation set is taking
135- // too long to complete.
136- var previousUpdateTime = validationSet . Updated ;
137-
138- await _validationStorageService . UpdateValidationSetAsync ( validationSet ) ;
139-
140- var validationSetDuration = validationSet . Updated - validationSet . Created ;
141- var previousDuration = previousUpdateTime - validationSet . Created ;
142-
143- // Only send a "validating taking too long" notice once. This is ensured by verifying this is
144- // the package's first validation set and that this is the first time the validation set duration
145- // is greater than the configured threshold. Service Bus message duplication for a single validation
146- // set will not cause multiple notices to be sent due to the row version on PackageValidationSet.
147- if ( validationSetDuration > _validationConfiguration . ValidationSetNotificationTimeout &&
148- previousDuration <= _validationConfiguration . ValidationSetNotificationTimeout &&
149- await _validationStorageService . GetValidationSetCountAsync ( package . Key ) == 1 )
150- {
151- _logger . LogWarning ( "Sending message that validation set {ValidationTrackingId} for package {PackageId} {PackageVersion} is taking too long" ,
152- validationSet . ValidationTrackingId ,
153- validationSet . PackageId ,
154- validationSet . PackageNormalizedVersion ) ;
155-
156- _messageService . SendPackageValidationTakingTooLongMessage ( package ) ;
157- _telemetryService . TrackSentValidationTakingTooLongMessage ( package . PackageRegistration . Id , package . NormalizedVersion , validationSet . ValidationTrackingId ) ;
158- }
159-
160- // Track any validations that are past their expected thresholds.
161- var timedOutValidations = GetIncompleteTimedOutValidations ( validationSet ) ;
162-
163- if ( timedOutValidations . Any ( ) )
130+ if ( currentCallStats . AnyRequiredValidationSucceeded )
164131 {
165- foreach ( var validation in timedOutValidations )
166- {
167- var duration = DateTime . UtcNow - validation . Started ;
168-
169- _logger . LogWarning ( "Validation {Validation} for package {PackageId} {PackageVersion} is past its expected duration after {Duration}" ,
170- validation . Type ,
171- validationSet . PackageId ,
172- validationSet . PackageNormalizedVersion ,
173- duration ) ;
174-
175- _telemetryService . TrackValidatorTimeout ( validation . Type ) ;
176- }
132+ TrackValidationSetCompletion ( package , validationSet , isSuccess : true ) ;
177133 }
178134
179- // Schedule another check if we haven't reached the validation set timeout yet.
180- if ( validationSetDuration <= _validationConfiguration . TimeoutValidationSetAfter )
135+ if ( AreOptionalValidationsRunning ( validationSet ) )
181136 {
182- var messageData = new PackageValidationMessageData ( package . PackageRegistration . Id , package . Version , validationSet . ValidationTrackingId ) ;
183- var postponeUntil = DateTimeOffset . UtcNow + _validationConfiguration . ValidationMessageRecheckPeriod ;
184-
185- await _validationEnqueuer . StartValidationAsync ( messageData , postponeUntil ) ;
137+ await ScheduleCheckIfNotTimedOut ( validationSet , package , tooLongNotificationAllowed : false ) ;
186138 }
187139 else
188140 {
189- _telemetryService . TrackValidationSetTimeout ( package . PackageRegistration . Id , package . NormalizedVersion , validationSet . ValidationTrackingId ) ;
141+ await CleanupValidationStorageAsync ( validationSet ) ;
190142 }
191143 }
144+ else
145+ {
146+ await ScheduleCheckIfNotTimedOut ( validationSet , package , tooLongNotificationAllowed : true ) ;
147+ }
192148 }
193149
194- private async Task CompleteValidationSetAsync ( Package package , PackageValidationSet validationSet , bool isSuccess )
150+ private void TrackValidationSetCompletion ( Package package , PackageValidationSet validationSet , bool isSuccess )
195151 {
196- await _packageFileService . DeletePackageForValidationSetAsync ( validationSet ) ;
197-
198152 _logger . LogInformation ( "Done processing {PackageId} {PackageVersion} {ValidationSetId} with IsSuccess = {IsSuccess}." ,
199153 package . PackageRegistration . Id ,
200154 package . NormalizedVersion ,
@@ -204,6 +158,11 @@ private async Task CompleteValidationSetAsync(Package package, PackageValidation
204158 TrackTotalValidationDuration ( validationSet , isSuccess ) ;
205159 }
206160
161+ private async Task CleanupValidationStorageAsync ( PackageValidationSet validationSet )
162+ {
163+ await _packageFileService . DeletePackageForValidationSetAsync ( validationSet ) ;
164+ }
165+
207166 private ValidationConfigurationItem GetValidationConfigurationItemByName ( string name )
208167 {
209168 _validationConfigurationsByName . TryGetValue ( name , out var item ) ;
@@ -218,14 +177,22 @@ private void TrackTotalValidationDuration(PackageValidationSet validationSet, bo
218177 isSuccess ) ;
219178 }
220179
221- private bool AllValidationsSucceeded ( PackageValidationSet packageValidationSet )
180+ private bool AllRequiredValidationsSucceeded ( PackageValidationSet packageValidationSet )
222181 {
223182 return packageValidationSet
224183 . PackageValidations
225184 . All ( pv => pv . ValidationStatus == ValidationStatus . Succeeded
226185 || GetValidationConfigurationItemByName ( pv . Type ) ? . FailureBehavior == ValidationFailureBehavior . AllowedToFail ) ;
227186 }
228187
188+ private bool AreOptionalValidationsRunning ( PackageValidationSet packageValidationSet )
189+ {
190+ return packageValidationSet
191+ . PackageValidations
192+ . Any ( pv => pv . ValidationStatus == ValidationStatus . Incomplete
193+ && GetValidationConfigurationItemByName ( pv . Type ) ? . FailureBehavior == ValidationFailureBehavior . AllowedToFail ) ;
194+ }
195+
229196 private List < PackageValidation > GetFailedValidations ( PackageValidationSet packageValidationSet )
230197 {
231198 return packageValidationSet
@@ -251,5 +218,82 @@ bool IsPackageValidationTimedOut(PackageValidation validation)
251218 . Where ( IsPackageValidationTimedOut )
252219 . ToList ( ) ;
253220 }
221+
222+ private async Task < TimeSpan > UpdateValidationDurationAsync ( PackageValidationSet validationSet , Package package , bool tooLongNotificationAllowed )
223+ {
224+ // There are no failed validations and some validations are still in progress. Update
225+ // the validation set's Updated field and send a notice if the validation set is taking
226+ // too long to complete.
227+ var previousUpdateTime = validationSet . Updated ;
228+
229+ await _validationStorageService . UpdateValidationSetAsync ( validationSet ) ;
230+
231+ var validationSetDuration = validationSet . Updated - validationSet . Created ;
232+ var previousDuration = previousUpdateTime - validationSet . Created ;
233+
234+ // Only send a "validating taking too long" notice once. This is ensured by verifying this is
235+ // the package's first validation set and that this is the first time the validation set duration
236+ // is greater than the configured threshold. Service Bus message duplication for a single validation
237+ // set will not cause multiple notices to be sent due to the row version on PackageValidationSet.
238+ if ( tooLongNotificationAllowed &&
239+ validationSetDuration > _validationConfiguration . ValidationSetNotificationTimeout &&
240+ previousDuration <= _validationConfiguration . ValidationSetNotificationTimeout &&
241+ await _validationStorageService . GetValidationSetCountAsync ( package . Key ) == 1 )
242+ {
243+ _logger . LogWarning ( "Sending message that validation set {ValidationTrackingId} for package {PackageId} {PackageVersion} is taking too long" ,
244+ validationSet . ValidationTrackingId ,
245+ validationSet . PackageId ,
246+ validationSet . PackageNormalizedVersion ) ;
247+
248+ _messageService . SendPackageValidationTakingTooLongMessage ( package ) ;
249+ _telemetryService . TrackSentValidationTakingTooLongMessage ( package . PackageRegistration . Id , package . NormalizedVersion , validationSet . ValidationTrackingId ) ;
250+ }
251+
252+ // Track any validations that are past their expected thresholds.
253+ var timedOutValidations = GetIncompleteTimedOutValidations ( validationSet ) ;
254+
255+ if ( timedOutValidations . Any ( ) )
256+ {
257+ foreach ( var validation in timedOutValidations )
258+ {
259+ var duration = DateTime . UtcNow - validation . Started ;
260+
261+ _logger . LogWarning ( "Validation {Validation} for package {PackageId} {PackageVersion} is past its expected duration after {Duration}" ,
262+ validation . Type ,
263+ validationSet . PackageId ,
264+ validationSet . PackageNormalizedVersion ,
265+ duration ) ;
266+
267+ _telemetryService . TrackValidatorTimeout ( validation . Type ) ;
268+ }
269+ }
270+
271+ return validationSetDuration ;
272+ }
273+
274+ private async Task ScheduleCheckIfNotTimedOut ( PackageValidationSet validationSet , Package package , bool tooLongNotificationAllowed )
275+ {
276+ var validationSetDuration = await UpdateValidationDurationAsync ( validationSet , package , tooLongNotificationAllowed ) ;
277+
278+ // Schedule another check if we haven't reached the validation set timeout yet.
279+ if ( validationSetDuration <= _validationConfiguration . TimeoutValidationSetAfter )
280+ {
281+ var messageData = new PackageValidationMessageData ( package . PackageRegistration . Id , package . Version , validationSet . ValidationTrackingId ) ;
282+ var postponeUntil = DateTimeOffset . UtcNow + _validationConfiguration . ValidationMessageRecheckPeriod ;
283+
284+ await _validationEnqueuer . StartValidationAsync ( messageData , postponeUntil ) ;
285+ }
286+ else
287+ {
288+ _logger . LogWarning ( "Abandoning checking status of validation set {ValidationTrackingId} for " +
289+ "package {PackageId} {PackageVersion} because it took too long (Duration: {Duration}, CutOffDuration: {CutOffDuration})" ,
290+ validationSet . ValidationTrackingId ,
291+ validationSet . PackageId ,
292+ validationSet . PackageNormalizedVersion ,
293+ validationSetDuration ,
294+ _validationConfiguration . TimeoutValidationSetAfter ) ;
295+ _telemetryService . TrackValidationSetTimeout ( package . PackageRegistration . Id , package . NormalizedVersion , validationSet . ValidationTrackingId ) ;
296+ }
297+ }
254298 }
255299}
0 commit comments