This repository has been archived by the owner on Nov 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
This reverts commit c69deed.
- Loading branch information
1 parent
6746111
commit 79a22ec
Showing
57 changed files
with
793 additions
and
1,381 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
using System.Text.Json; | ||
using Microsoft.Azure.Functions.Worker; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; | ||
namespace Microsoft.OneFuzz.Service.Functions; | ||
|
||
|
||
public class QueueJobResult { | ||
private readonly ILogger _log; | ||
private readonly IOnefuzzContext _context; | ||
|
||
public QueueJobResult(ILogger<QueueJobResult> logTracer, IOnefuzzContext context) { | ||
_log = logTracer; | ||
_context = context; | ||
} | ||
|
||
[Function("QueueJobResult")] | ||
public async Async.Task Run([QueueTrigger("job-result", Connection = "AzureWebJobsStorage")] string msg) { | ||
|
||
var _tasks = _context.TaskOperations; | ||
var _jobs = _context.JobOperations; | ||
|
||
_log.LogInformation("job result: {msg}", msg); | ||
var jr = JsonSerializer.Deserialize<TaskJobResultEntry>(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); | ||
|
||
var task = await _tasks.GetByTaskId(jr.TaskId); | ||
if (task == null) { | ||
_log.LogWarning("invalid {TaskId}", jr.TaskId); | ||
return; | ||
} | ||
|
||
var job = await _jobs.Get(task.JobId); | ||
if (job == null) { | ||
_log.LogWarning("invalid {JobId}", task.JobId); | ||
return; | ||
} | ||
|
||
JobResultData? data = jr.Data; | ||
if (data == null) { | ||
_log.LogWarning($"job result data is empty, throwing out: {jr}"); | ||
return; | ||
} | ||
|
||
var jobResultType = data.Type; | ||
_log.LogInformation($"job result data type: {jobResultType}"); | ||
|
||
Dictionary<string, double> value; | ||
if (jr.Value.Count > 0) { | ||
value = jr.Value; | ||
} else { | ||
_log.LogWarning($"job result data is empty, throwing out: {jr}"); | ||
return; | ||
} | ||
|
||
var jobResult = await _context.JobResultOperations.CreateOrUpdate(job.JobId, jobResultType, value); | ||
if (!jobResult.IsOk) { | ||
_log.LogError("failed to create or update with job result {JobId}", job.JobId); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
src/ApiService/ApiService/onefuzzlib/JobResultOperations.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
using ApiService.OneFuzzLib.Orm; | ||
using Microsoft.Extensions.Logging; | ||
using Polly; | ||
namespace Microsoft.OneFuzz.Service; | ||
|
||
public interface IJobResultOperations : IOrm<JobResult> { | ||
|
||
Async.Task<JobResult?> GetJobResult(Guid jobId); | ||
Async.Task<OneFuzzResultVoid> CreateOrUpdate(Guid jobId, JobResultType resultType, Dictionary<string, double> resultValue); | ||
|
||
} | ||
public class JobResultOperations : Orm<JobResult>, IJobResultOperations { | ||
|
||
public JobResultOperations(ILogger<JobResultOperations> log, IOnefuzzContext context) | ||
: base(log, context) { | ||
} | ||
|
||
public async Async.Task<JobResult?> GetJobResult(Guid jobId) { | ||
return await SearchByPartitionKeys(new[] { jobId.ToString() }).SingleOrDefaultAsync(); | ||
} | ||
|
||
private JobResult UpdateResult(JobResult result, JobResultType type, Dictionary<string, double> resultValue) { | ||
|
||
var newResult = result; | ||
double newValue; | ||
switch (type) { | ||
case JobResultType.NewCrashingInput: | ||
newValue = result.NewCrashingInput + resultValue["count"]; | ||
newResult = result with { NewCrashingInput = newValue }; | ||
break; | ||
case JobResultType.NewReport: | ||
newValue = result.NewReport + resultValue["count"]; | ||
newResult = result with { NewReport = newValue }; | ||
break; | ||
case JobResultType.NewUniqueReport: | ||
newValue = result.NewUniqueReport + resultValue["count"]; | ||
newResult = result with { NewUniqueReport = newValue }; | ||
break; | ||
case JobResultType.NewRegressionReport: | ||
newValue = result.NewRegressionReport + resultValue["count"]; | ||
newResult = result with { NewRegressionReport = newValue }; | ||
break; | ||
case JobResultType.NewCrashDump: | ||
newValue = result.NewCrashDump + resultValue["count"]; | ||
newResult = result with { NewCrashDump = newValue }; | ||
break; | ||
case JobResultType.CoverageData: | ||
double newCovered = resultValue["covered"]; | ||
double newTotalCovered = resultValue["features"]; | ||
double newCoverageRate = resultValue["rate"]; | ||
newResult = result with { InstructionsCovered = newCovered, TotalInstructions = newTotalCovered, CoverageRate = newCoverageRate }; | ||
break; | ||
case JobResultType.RuntimeStats: | ||
double newTotalIterations = resultValue["total_count"]; | ||
newResult = result with { IterationCount = newTotalIterations }; | ||
break; | ||
default: | ||
_logTracer.LogWarning($"Invalid Field {type}."); | ||
break; | ||
} | ||
_logTracer.LogInformation($"Attempting to log new result: {newResult}"); | ||
return newResult; | ||
} | ||
|
||
private async Async.Task<bool> TryUpdate(Job job, JobResultType resultType, Dictionary<string, double> resultValue) { | ||
var jobId = job.JobId; | ||
|
||
var jobResult = await GetJobResult(jobId); | ||
|
||
if (jobResult == null) { | ||
_logTracer.LogInformation("Creating new JobResult for Job {JobId}", jobId); | ||
|
||
var entry = new JobResult(JobId: jobId, Project: job.Config.Project, Name: job.Config.Name); | ||
|
||
jobResult = UpdateResult(entry, resultType, resultValue); | ||
|
||
var r = await Insert(jobResult); | ||
if (!r.IsOk) { | ||
throw new InvalidOperationException($"failed to insert job result {jobResult.JobId}"); | ||
} | ||
_logTracer.LogInformation("created job result {JobId}", jobResult.JobId); | ||
} else { | ||
_logTracer.LogInformation("Updating existing JobResult entry for Job {JobId}", jobId); | ||
|
||
jobResult = UpdateResult(jobResult, resultType, resultValue); | ||
|
||
var r = await Update(jobResult); | ||
if (!r.IsOk) { | ||
throw new InvalidOperationException($"failed to insert job result {jobResult.JobId}"); | ||
} | ||
_logTracer.LogInformation("updated job result {JobId}", jobResult.JobId); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public async Async.Task<OneFuzzResultVoid> CreateOrUpdate(Guid jobId, JobResultType resultType, Dictionary<string, double> resultValue) { | ||
|
||
var job = await _context.JobOperations.Get(jobId); | ||
if (job == null) { | ||
return OneFuzzResultVoid.Error(ErrorCode.INVALID_REQUEST, "invalid job"); | ||
} | ||
|
||
var success = false; | ||
try { | ||
_logTracer.LogInformation("attempt to update job result {JobId}", job.JobId); | ||
var policy = Policy.Handle<InvalidOperationException>().WaitAndRetryAsync(50, _ => new TimeSpan(0, 0, 5)); | ||
await policy.ExecuteAsync(async () => { | ||
success = await TryUpdate(job, resultType, resultValue); | ||
_logTracer.LogInformation("attempt {success}", success); | ||
}); | ||
return OneFuzzResultVoid.Ok; | ||
} catch (Exception e) { | ||
return OneFuzzResultVoid.Error(ErrorCode.UNABLE_TO_UPDATE, new string[] { | ||
$"Unexpected failure when attempting to update job result for {job.JobId}", | ||
$"Exception: {e}" | ||
}); | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.