@@ -113,6 +113,59 @@ public async Task<IActionResult> GetOverviewAsync([FromQuery] DateTime startTime
113113 }
114114 }
115115
116+ /// <summary>
117+ /// Get execution daily stats for a given time period.
118+ /// </summary>
119+ /// <param name="filter">TimeFiler defining start and end times, plus paging options.</param>
120+ /// <param name="workflowId">WorkflowId if you want stats just for a given workflow. (both workflowId and TaskId must be given, if you give one).</param>
121+ /// <returns>a paged obect with all the stat details.</returns>
122+ [ ProducesResponseType ( typeof ( StatsPagedResponse < List < ExecutionStatDTO > > ) , StatusCodes . Status200OK ) ]
123+ [ ProducesResponseType ( typeof ( ProblemDetails ) , StatusCodes . Status500InternalServerError ) ]
124+ [ HttpGet ( "dailystats" ) ]
125+ public async Task < IActionResult > GetDailyStatsAsync ( [ FromQuery ] TimeFilter filter , string workflowId = "" )
126+ {
127+ SetUpFilter ( filter , out var route , out var pageSize , out var validFilter ) ;
128+
129+ try
130+ {
131+ var allStats = await _repository . GetAllStatsAsync ( filter . StartTime , filter . EndTime , workflowId , string . Empty ) ;
132+ var statsDto = allStats
133+ . OrderBy ( a => a . StartedUTC )
134+ . GroupBy ( s => s . StartedUTC . Date )
135+ . Select ( g => new ExecutionStatDayOverview
136+ {
137+ Date = DateOnly . FromDateTime ( g . Key . Date ) ,
138+ TotalExecutions = g . Count ( ) ,
139+ TotalFailures = g . Count ( i => string . Compare ( i . Status , "Failed" , true ) == 0 ) ,
140+ TotalApprovals = g . Count ( i => string . Compare ( i . Status , ApplicationReviewStatus . Approved . ToString ( ) , true ) == 0 ) ,
141+ TotalRejections = g . Count ( i => string . Compare ( i . Status , ApplicationReviewStatus . Rejected . ToString ( ) , true ) == 0 ) ,
142+ TotalCancelled = g . Count ( i => string . Compare ( i . Status , ApplicationReviewStatus . Cancelled . ToString ( ) , true ) == 0 ) ,
143+ TotalAwaitingReview = g . Count ( i => string . Compare ( i . Status , ApplicationReviewStatus . AwaitingReview . ToString ( ) , true ) == 0 ) ,
144+ } ) ;
145+
146+ var pagedStats = statsDto . Skip ( ( filter . PageNumber - 1 ) * pageSize ) . Take ( pageSize ) ;
147+
148+ var res = CreateStatsPagedResponse ( pagedStats , validFilter , statsDto . Count ( ) , _uriService , route ) ;
149+ var ( avgTotalExecution , avgArgoExecution ) = await _repository . GetAverageStats ( filter . StartTime , filter . EndTime , workflowId , string . Empty ) ;
150+
151+ res . PeriodStart = filter . StartTime ;
152+ res . PeriodEnd = filter . EndTime ;
153+ res . TotalExecutions = allStats . Count ( ) ;
154+ res . TotalSucceeded = statsDto . Sum ( s => s . TotalApprovals ) ;
155+ res . TotalFailures = statsDto . Sum ( s => s . TotalFailures ) ;
156+ res . TotalInprogress = statsDto . Sum ( s => s . TotalAwaitingReview ) ;
157+ res . AverageTotalExecutionSeconds = Math . Round ( avgTotalExecution , 2 ) ;
158+ res . AverageArgoExecutionSeconds = Math . Round ( avgArgoExecution , 2 ) ;
159+
160+ return Ok ( res ) ;
161+ }
162+ catch ( Exception e )
163+ {
164+ _logger . GetStatsAsyncError ( e ) ;
165+ return Problem ( $ "Unexpected error occurred: { e . Message } ", $ "tasks/stats", InternalServerError ) ;
166+ }
167+ }
168+
116169 /// <summary>
117170 /// Get execution stats for a given time period.
118171 /// </summary>
@@ -133,63 +186,71 @@ public async Task<IActionResult> GetStatsAsync([FromQuery] TimeFilter filter, st
133186 return Problem ( "Failed to validate ids, not a valid guid" , "tasks/stats/" , BadRequest ) ;
134187 }
135188
136- if ( filter . EndTime == default )
137- {
138- filter . EndTime = DateTime . Now ;
139- }
189+ SetUpFilter ( filter , out var route , out var pageSize , out var validFilter ) ;
140190
141- if ( filter . StartTime == default )
191+ try
142192 {
143- filter . StartTime = new DateTime ( 2023 , 1 , 1 ) ;
144- }
145-
146- var route = Request ? . Path . Value ?? string . Empty ;
147- var pageSize = filter . PageSize ?? Options . Value . EndpointSettings ? . DefaultPageSize ?? 10 ;
148- var max = Options . Value . EndpointSettings ? . MaxPageSize ?? 20 ;
149- var validFilter = new PaginationFilter ( filter . PageNumber , pageSize , max ) ;
193+ var allStats = await _repository . GetStatsAsync ( filter . StartTime , filter . EndTime , pageSize , filter . PageNumber , workflowId , taskId ) ;
194+ var statsDto = allStats
195+ . OrderBy ( a => a . StartedUTC )
196+ . Select ( s => new ExecutionStatDTO ( s ) ) ;
150197
151- try
198+ var res = await GatherPagedStats ( filter , workflowId , taskId , route , validFilter , statsDto ) ;
199+ return Ok ( res ) ;
200+ }
201+ catch ( Exception e )
152202 {
153- workflowId ??= string . Empty ;
154- taskId ??= string . Empty ;
155- var allStats = _repository . GetStatsAsync ( filter . StartTime , filter . EndTime , pageSize , filter . PageNumber , workflowId , taskId ) ;
203+ _logger . GetStatsAsyncError ( e ) ;
204+ return Problem ( $ "Unexpected error occurred: { e . Message } ", $ "tasks/stats", InternalServerError ) ;
205+ }
206+ }
156207
157- var successes = _repository . GetStatsStatusSucceededCountAsync ( filter . StartTime , filter . EndTime , workflowId , taskId ) ;
208+ private async Task < StatsPagedResponse < IEnumerable < T > > > GatherPagedStats < T > ( TimeFilter filter , string workflowId , string taskId , string route , PaginationFilter validFilter , IEnumerable < T > statsDto )
209+ {
210+ workflowId ??= string . Empty ;
211+ taskId ??= string . Empty ;
158212
159- var fails = _repository . GetStatsStatusFailedCountAsync ( filter . StartTime , filter . EndTime , workflowId , taskId ) ;
213+ var successes = _repository . GetStatsStatusSucceededCountAsync ( filter . StartTime , filter . EndTime , workflowId , taskId ) ;
160214
161- var rangeCount = _repository . GetStatsTotalCompleteExecutionsCountAsync ( filter . StartTime , filter . EndTime , workflowId , taskId ) ;
215+ var fails = _repository . GetStatsStatusFailedCountAsync ( filter . StartTime , filter . EndTime , workflowId , taskId ) ;
162216
163- var stats = _repository . GetAverageStats ( filter . StartTime , filter . EndTime , workflowId , taskId ) ;
217+ var rangeCount = _repository . GetStatsTotalCompleteExecutionsCountAsync ( filter . StartTime , filter . EndTime , workflowId , taskId ) ;
164218
165- var running = _repository . GetStatsStatusCountAsync ( filter . StartTime , filter . EndTime , TaskExecutionStatus . Accepted . ToString ( ) , workflowId , taskId ) ;
219+ var stats = _repository . GetAverageStats ( filter . StartTime , filter . EndTime , workflowId , taskId ) ;
166220
167- await Task . WhenAll ( allStats , fails , rangeCount , stats , running ) ;
221+ var running = _repository . GetStatsStatusCountAsync ( filter . StartTime , filter . EndTime , TaskExecutionStatus . Accepted . ToString ( ) , workflowId , taskId ) ;
168222
169- ExecutionStatDTO [ ] statsDto ;
223+ await Task . WhenAll ( fails , rangeCount , stats , running ) ;
170224
171- statsDto = allStats . Result
172- . OrderBy ( a => a . StartedUTC )
173- . Select ( s => new ExecutionStatDTO ( s ) )
174- . ToArray ( ) ;
225+ var res = CreateStatsPagedResponse ( statsDto , validFilter , rangeCount . Result , _uriService , route ) ;
175226
176- var res = CreateStatsPagedResponse ( statsDto , validFilter , rangeCount . Result , _uriService , route ) ;
227+ res . PeriodStart = filter . StartTime ;
228+ res . PeriodEnd = filter . EndTime ;
229+ res . TotalExecutions = rangeCount . Result ;
230+ res . TotalSucceeded = successes . Result ;
231+ res . TotalFailures = fails . Result ;
232+ res . TotalInprogress = running . Result ;
233+ res . AverageTotalExecutionSeconds = Math . Round ( stats . Result . avgTotalExecution , 2 ) ;
234+ res . AverageArgoExecutionSeconds = Math . Round ( stats . Result . avgArgoExecution , 2 ) ;
235+ return res ;
236+ }
177237
178- res . PeriodStart = filter . StartTime ;
179- res . PeriodEnd = filter . EndTime ;
180- res . TotalExecutions = rangeCount . Result ;
181- res . TotalSucceeded = successes . Result ;
182- res . TotalFailures = fails . Result ;
183- res . TotalInprogress = running . Result ;
184- res . AverageTotalExecutionSeconds = Math . Round ( stats . Result . avgTotalExecution , 2 ) ;
185- res . AverageArgoExecutionSeconds = Math . Round ( stats . Result . avgArgoExecution , 2 ) ;
186- return Ok ( res ) ;
238+ private void SetUpFilter ( TimeFilter filter , out string route , out int pageSize , out PaginationFilter validFilter )
239+ {
240+ if ( filter . EndTime == default )
241+ {
242+ filter . EndTime = DateTime . Now ;
187243 }
188- catch ( Exception e )
244+
245+ if ( filter . StartTime == default )
189246 {
190- _logger . GetStatsAsyncError ( e ) ;
191- return Problem ( $ "Unexpected error occurred: { e . Message } ", $ "tasks/stats", InternalServerError ) ;
247+ filter . StartTime = new DateTime ( 2023 , 1 , 1 ) ;
192248 }
249+
250+ route = Request ? . Path . Value ?? string . Empty ;
251+ pageSize = filter . PageSize ?? Options . Value . EndpointSettings ? . DefaultPageSize ?? 10 ;
252+ var max = Options . Value . EndpointSettings ? . MaxPageSize ?? 20 ;
253+ validFilter = new PaginationFilter ( filter . PageNumber , pageSize , max ) ;
193254 }
194255 }
195256}
0 commit comments