-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automatic scheduling of missions #2033
Open
mrica-equinor
wants to merge
1
commit into
equinor:main
Choose a base branch
from
mrica-equinor:auto-achedule-missions
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+392
−4
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
206 changes: 206 additions & 0 deletions
206
backend/api/HostedServices/InspectionFrequencyHostedService.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,206 @@ | ||
using System; | ||
using Api.Controllers.Models; | ||
using Api.Database.Models; | ||
using Api.Services; | ||
using Api.Services.MissionLoaders; | ||
using Api.Utilities; | ||
using Hangfire; | ||
|
||
namespace Api.HostedServices | ||
{ | ||
public class InspectionFrequencyHostedService : IHostedService, IDisposable | ||
{ | ||
private readonly ILogger<InspectionFrequencyHostedService> _logger; | ||
private readonly IServiceScopeFactory _scopeFactory; | ||
private Timer? _timer = null; | ||
|
||
public InspectionFrequencyHostedService( | ||
ILogger<InspectionFrequencyHostedService> logger, | ||
IServiceScopeFactory scopeFactory | ||
) | ||
{ | ||
_logger = logger; | ||
_scopeFactory = scopeFactory; | ||
} | ||
|
||
private IMissionDefinitionService MissionDefinitionService => | ||
_scopeFactory | ||
.CreateScope() | ||
.ServiceProvider.GetRequiredService<IMissionDefinitionService>(); | ||
|
||
private IMissionSchedulingService MissionSchedulingService => | ||
_scopeFactory | ||
.CreateScope() | ||
.ServiceProvider.GetRequiredService<IMissionSchedulingService>(); | ||
|
||
private IRobotService RobotService => | ||
_scopeFactory.CreateScope().ServiceProvider.GetRequiredService<IRobotService>(); | ||
|
||
private IMissionLoader MissionLoader => | ||
_scopeFactory.CreateScope().ServiceProvider.GetRequiredService<IMissionLoader>(); | ||
|
||
public Task StartAsync(CancellationToken stoppingToken) | ||
{ | ||
_logger.LogInformation("Inspection Frequency Hosted Service Running."); | ||
|
||
var timeUntilMidnight = (DateTime.UtcNow.AddDays(1) - DateTime.UtcNow).TotalSeconds; | ||
_timer = new Timer( | ||
DoWork, | ||
null, | ||
TimeSpan.FromSeconds(timeUntilMidnight), | ||
TimeSpan.FromDays(1) | ||
); | ||
return Task.CompletedTask; | ||
} | ||
|
||
private async void DoWork(object? state) | ||
{ | ||
var missionQuery = new MissionDefinitionQueryStringParameters(); | ||
|
||
List<MissionDefinition>? missionDefinitions; | ||
try | ||
{ | ||
missionDefinitions = await MissionDefinitionService.ReadByHasInspectionFrequency(); | ||
} | ||
catch (InvalidDataException e) | ||
{ | ||
_logger.LogError(e, "{ErrorMessage}", e.Message); | ||
return; | ||
} | ||
|
||
if (missionDefinitions == null) | ||
{ | ||
_logger.LogInformation("No mission definitions with inspection frequency found."); | ||
return; | ||
} | ||
|
||
var selectedMissionDefinitions = missionDefinitions.Where(m => | ||
m.AutoScheduleFrequency != null | ||
&& m.AutoScheduleFrequency.GetSchedulingTimesForNext24Hours() != null | ||
); | ||
|
||
if (selectedMissionDefinitions.Any() == false) | ||
{ | ||
_logger.LogInformation( | ||
"No mission definitions with inspection frequency found that are due for inspection today." | ||
); | ||
return; | ||
} | ||
|
||
foreach (var missionDefinition in selectedMissionDefinitions) | ||
{ | ||
var jobDelays = | ||
missionDefinition.AutoScheduleFrequency!.GetSchedulingTimesForNext24Hours(); | ||
|
||
if (jobDelays == null) | ||
{ | ||
_logger.LogWarning( | ||
"No job schedules found for mission definition {MissionDefinitionId}.", | ||
missionDefinition.Id | ||
); | ||
return; | ||
} | ||
|
||
foreach (var jobDelay in jobDelays) | ||
{ | ||
_logger.LogInformation( | ||
"Scheduling mission run for mission definition {MissionDefinitionId} in {TimeLeft}.", | ||
missionDefinition.Id, | ||
jobDelay | ||
); | ||
BackgroundJob.Schedule( | ||
() => AutomaticScheduleMissionRun(missionDefinition), | ||
jobDelay | ||
); | ||
} | ||
} | ||
} | ||
|
||
public async Task AutomaticScheduleMissionRun(MissionDefinition missionDefinition) | ||
{ | ||
_logger.LogInformation( | ||
"Scheduling mission run for mission definition {MissionDefinitionId}.", | ||
missionDefinition.Id | ||
); | ||
|
||
if (missionDefinition.InspectionArea == null) | ||
{ | ||
_logger.LogWarning( | ||
"Mission definition {MissionDefinitionId} has no inspection area.", | ||
missionDefinition.Id | ||
); | ||
return; | ||
} | ||
|
||
IList<Robot> robots; | ||
try | ||
{ | ||
robots = await RobotService.ReadRobotsForInstallation( | ||
missionDefinition.InstallationCode | ||
); | ||
} | ||
catch (Exception e) | ||
{ | ||
_logger.LogError(e, "{ErrorMessage}", e.Message); | ||
return; | ||
} | ||
|
||
if (robots == null) | ||
{ | ||
_logger.LogInformation( | ||
"No robots found for installation code {InstallationCode}.", | ||
missionDefinition.InstallationCode | ||
); | ||
return; | ||
} | ||
|
||
var robot = robots.FirstOrDefault(r => | ||
r.CurrentInspectionArea?.Id == missionDefinition.InspectionArea.Id | ||
); | ||
if (robot == null) | ||
{ | ||
_logger.LogWarning( | ||
"No robot found for mission definition {MissionDefinitionId} and inspection area {InspectionAreaId}.", | ||
missionDefinition.Id, | ||
missionDefinition.InspectionArea.Id | ||
); | ||
return; | ||
} | ||
|
||
_logger.LogInformation( | ||
"Scheduling mission run for mission definition {MissionDefinitionId} and robot {RobotId}.", | ||
missionDefinition.Id, | ||
robot.Id | ||
); | ||
|
||
try | ||
{ | ||
await MissionSchedulingService.ScheduleMissionRunFromMissionDefinitionLastSuccessfullRun( | ||
missionDefinition.Id, | ||
robot.Id | ||
); | ||
} | ||
catch (Exception e) | ||
{ | ||
_logger.LogError(e, "{ErrorMessage}", e.Message); | ||
return; | ||
} | ||
|
||
return; | ||
} | ||
|
||
public Task StopAsync(CancellationToken stoppingToken) | ||
{ | ||
_logger.LogInformation("Inspection Frequency Hosted Service is stopping."); | ||
|
||
_timer?.Change(Timeout.Infinite, 0); | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_timer?.Dispose(); | ||
} | ||
} | ||
} |
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.