Skip to content

Commit

Permalink
Don't use potentially outdated robot after update
Browse files Browse the repository at this point in the history
  • Loading branch information
andchiind authored and oysand committed Dec 17, 2024
1 parent d924d00 commit 7996d46
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 78 deletions.
2 changes: 1 addition & 1 deletion backend/api/Controllers/Models/UpdateRobotQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
public class UpdateRobotQuery
{
public string? AreaId { get; set; }
public string? InspectionAreaId { get; set; }

public Pose? Pose { get; set; }

Expand Down
42 changes: 24 additions & 18 deletions backend/api/Controllers/RobotController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class RobotController(
IIsarService isarService,
IMissionSchedulingService missionSchedulingService,
IRobotModelService robotModelService,
IAreaService areaService,
IDeckService deckService,
IErrorHandlingService errorHandlingService
) : ControllerBase
{
Expand Down Expand Up @@ -163,8 +163,8 @@ [FromBody] Robot robot

try
{
var updatedRobot = await robotService.Update(robot);
var robotResponse = new RobotResponse(updatedRobot);
await robotService.Update(robot);
var robotResponse = new RobotResponse(robot);
logger.LogInformation("Successful PUT of robot to database");

return Ok(robotResponse);
Expand Down Expand Up @@ -215,31 +215,36 @@ [FromBody] UpdateRobotQuery query
return NotFound(errorMessage);
}

Robot updatedRobot;
switch (fieldName)
{
case "currentInspectionAreaId":
if (query.AreaId == null)
updatedRobot = await robotService.UpdateCurrentInspectionArea(id, null);
if (query.InspectionAreaId == null)
{
await robotService.UpdateCurrentInspectionArea(id, null);
robot.CurrentInspectionArea = null;
}
else
{
var area = await areaService.ReadById(query.AreaId, readOnly: true);
if (area == null) return NotFound($"No area with ID {query.AreaId} was found");
updatedRobot = await robotService.UpdateCurrentInspectionArea(id, area.Id);
var inspectionArea = await deckService.ReadById(query.InspectionAreaId, readOnly: true);
if (inspectionArea == null) return NotFound($"No inspection area with ID {query.InspectionAreaId} was found");
await robotService.UpdateCurrentInspectionArea(id, inspectionArea.Id);
robot.CurrentInspectionArea = inspectionArea;
}
break;
case "pose":
if (query.Pose == null) return BadRequest("Cannot set robot pose to null");
updatedRobot = await robotService.UpdateRobotPose(id, query.Pose);
await robotService.UpdateRobotPose(id, query.Pose);
robot.Pose = query.Pose;
break;
case "missionId":
updatedRobot = await robotService.UpdateCurrentMissionId(id, query.MissionId);
await robotService.UpdateCurrentMissionId(id, query.MissionId);
robot.CurrentMissionId = query.MissionId;
break;
default:
return NotFound($"Could not find any field with name {fieldName}");
}

var robotResponse = new RobotResponse(updatedRobot);
var robotResponse = new RobotResponse(robot);
logger.LogInformation("Successful PUT of robot to database");

return Ok(robotResponse);
Expand Down Expand Up @@ -284,10 +289,10 @@ [FromRoute] bool deprecated
return NotFound(errorMessage);
}

Robot updatedRobot;
updatedRobot = await robotService.UpdateDeprecated(id, deprecated);
await robotService.UpdateDeprecated(id, deprecated);
robot.Deprecated = deprecated;

var robotResponse = new RobotResponse(updatedRobot);
var robotResponse = new RobotResponse(robot);
logger.LogInformation("Successful updated deprecated on robot to database");

return Ok(robotResponse);
Expand Down Expand Up @@ -357,10 +362,11 @@ [FromBody] RobotStatus robotStatus

try
{
var updatedRobot = await robotService.UpdateRobotStatus(id, robotStatus);
logger.LogInformation("Successfully updated robot {RobotId}", updatedRobot.Id);
await robotService.UpdateRobotStatus(id, robotStatus);
robot.Status = robotStatus;
logger.LogInformation("Successfully updated robot {RobotId}", robot.Id);

var robotResponse = new RobotResponse(updatedRobot);
var robotResponse = new RobotResponse(robot);

if (robotStatus == RobotStatus.Available) missionSchedulingService.TriggerRobotAvailable(new RobotAvailableEventArgs(robot.Id));

Expand Down
4 changes: 2 additions & 2 deletions backend/api/EventHandlers/MqttEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ private async void OnIsarRobotInfo(object? sender, MqttReceivedArgs mqttArgs)
if (isarRobotInfo.Capabilities is not null) UpdateRobotCapabilitiesIfChanged(isarRobotInfo.Capabilities, ref robot, ref updatedFields);
if (updatedFields.Count < 1) return;

robot = await RobotService.Update(robot);
await RobotService.Update(robot);
_logger.LogInformation("Updated robot '{Id}' ('{RobotName}') in database: {Updates}", robot.Id, robot.Name, updatedFields);
}
finally
Expand Down Expand Up @@ -354,7 +354,7 @@ private async void OnIsarBatteryUpdate(object? sender, MqttReceivedArgs mqttArgs
var robot = await BatteryTimeseriesService.AddBatteryEntry(batteryStatus.BatteryLevel, batteryStatus.IsarId);
if (robot != null && robot.BatteryState != batteryStatus.BatteryState)
{
robot = await RobotService.UpdateRobotBatteryState(robot.Id, batteryStatus.BatteryState);
await RobotService.UpdateRobotBatteryState(robot.Id, batteryStatus.BatteryState);
}

_updateRobotSemaphore.Release();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public class BatteryTimeseriesService(ILogger<BatteryTimeseriesService> logger,
{
if (Math.Abs(batteryLevel - robot.BatteryLevel) > Tolerance)
{
robot = await robotService.UpdateRobotBatteryLevel(robot.Id, batteryLevel);
await robotService.UpdateRobotBatteryLevel(robot.Id, batteryLevel);
robot.BatteryLevel = batteryLevel;
}
}
catch (Exception e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public class PressureTimeseriesService(ILogger<PressureTimeseriesService> logger
{
if (robot.PressureLevel is null || Math.Abs(pressureLevel - (float)robot.PressureLevel) > Tolerance)
{
robot = await robotService.UpdateRobotPressureLevel(robot.Id, pressureLevel);
await robotService.UpdateRobotPressureLevel(robot.Id, pressureLevel);
robot.PressureLevel = pressureLevel;
}
}
catch (Exception e)
Expand Down
100 changes: 45 additions & 55 deletions backend/api/Services/RobotService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ public interface IRobotService
public Task<Robot?> ReadById(string id, bool readOnly = true);
public Task<Robot?> ReadByIsarId(string isarId, bool readOnly = true);
public Task<IList<Robot>> ReadRobotsForInstallation(string installationCode, bool readOnly = true);
public Task<Robot> Update(Robot robot);
public Task<Robot> UpdateRobotStatus(string robotId, RobotStatus status);
public Task<Robot> UpdateRobotBatteryLevel(string robotId, float batteryLevel);
public Task<Robot> UpdateRobotBatteryState(string robotId, BatteryState? batteryState);
public Task<Robot> UpdateRobotPressureLevel(string robotId, float? pressureLevel);
public Task<Robot> UpdateRobotPose(string robotId, Pose pose);
public Task<Robot> UpdateRobotIsarConnected(string robotId, bool isarConnected);
public Task<Robot> UpdateCurrentMissionId(string robotId, string? missionId);
public Task<Robot> UpdateCurrentInspectionArea(string robotId, string? inspectionAreaId);
public Task<Robot> UpdateDeprecated(string robotId, bool deprecated);
public Task<Robot> UpdateMissionQueueFrozen(string robotId, bool missionQueueFrozen);
public Task<Robot> UpdateFlotillaStatus(string robotId, RobotFlotillaStatus status);
public Task Update(Robot robot);
public Task UpdateRobotStatus(string robotId, RobotStatus status);
public Task UpdateRobotBatteryLevel(string robotId, float batteryLevel);
public Task UpdateRobotBatteryState(string robotId, BatteryState? batteryState);
public Task UpdateRobotPressureLevel(string robotId, float? pressureLevel);
public Task UpdateRobotPose(string robotId, Pose pose);
public Task UpdateRobotIsarConnected(string robotId, bool isarConnected);
public Task UpdateCurrentMissionId(string robotId, string? missionId);
public Task UpdateCurrentInspectionArea(string robotId, string? inspectionAreaId);
public Task UpdateDeprecated(string robotId, bool deprecated);
public Task UpdateMissionQueueFrozen(string robotId, bool missionQueueFrozen);
public Task UpdateFlotillaStatus(string robotId, RobotFlotillaStatus status);
public Task<Robot?> Delete(string id);
public void DetachTracking(Robot robot);
}
Expand Down Expand Up @@ -148,32 +148,24 @@ public async Task<Robot> GetRobotWithPreCheck(string robotId, bool readOnly = tr
return robot;
}

public async Task<Robot> UpdateRobotStatus(string robotId, RobotStatus status)
public async Task UpdateRobotStatus(string robotId, RobotStatus status)
{
var robot = await UpdateRobotProperty(robotId, "Status", status);
ThrowIfRobotIsNull(robot, robotId);
return robot;
await UpdateRobotProperty(robotId, "Status", status);
}

public async Task<Robot> UpdateRobotBatteryLevel(string robotId, float batteryLevel)
public async Task UpdateRobotBatteryLevel(string robotId, float batteryLevel)
{
var robot = await UpdateRobotProperty(robotId, "BatteryLevel", batteryLevel, isLogLevelDebug: true);
ThrowIfRobotIsNull(robot, robotId);
return robot;
await UpdateRobotProperty(robotId, "BatteryLevel", batteryLevel, isLogLevelDebug: true);
}

public async Task<Robot> UpdateRobotBatteryState(string robotId, BatteryState? batteryState)
public async Task UpdateRobotBatteryState(string robotId, BatteryState? batteryState)
{
var robot = await UpdateRobotProperty(robotId, "BatteryState", batteryState, isLogLevelDebug: true);
ThrowIfRobotIsNull(robot, robotId);
return robot;
await UpdateRobotProperty(robotId, "BatteryState", batteryState, isLogLevelDebug: true);
}

public async Task<Robot> UpdateRobotPressureLevel(string robotId, float? pressureLevel)
public async Task UpdateRobotPressureLevel(string robotId, float? pressureLevel)
{
var robot = await UpdateRobotProperty(robotId, "PressureLevel", pressureLevel);
ThrowIfRobotIsNull(robot, robotId);
return robot;
await UpdateRobotProperty(robotId, "PressureLevel", pressureLevel);
}

private void ThrowIfRobotIsNull(Robot? robot, string robotId)
Expand All @@ -185,7 +177,7 @@ private void ThrowIfRobotIsNull(Robot? robot, string robotId)
throw new RobotNotFoundException(errorMessage);
}

public async Task<Robot> UpdateRobotPose(string robotId, Pose pose)
public async Task UpdateRobotPose(string robotId, Pose pose)
{
var robotQuery = GetRobotsWithSubModels(readOnly: true).Where(robot => robot.Id == robotId);
var robot = await robotQuery.FirstOrDefaultAsync();
Expand All @@ -209,46 +201,46 @@ await robotQuery
ThrowIfRobotIsNull(robot, robotId);
NotifySignalROfUpdatedRobot(robot!, robot!.CurrentInstallation!);
DetachTracking(robot);

return robot;
}

public async Task<Robot> UpdateRobotIsarConnected(string robotId, bool isarConnected)
public async Task UpdateRobotIsarConnected(string robotId, bool isarConnected)
{
var robot = await UpdateRobotProperty(robotId, "IsarConnected", isarConnected);
ThrowIfRobotIsNull(robot, robotId);
return robot;
await UpdateRobotProperty(robotId, "IsarConnected", isarConnected);
}

public async Task<Robot> UpdateCurrentMissionId(string robotId, string? currentMissionId)
public async Task UpdateCurrentMissionId(string robotId, string? currentMissionId)
{
var robot = await UpdateRobotProperty(robotId, "CurrentMissionId", currentMissionId);
ThrowIfRobotIsNull(robot, robotId);
return robot;
await UpdateRobotProperty(robotId, "CurrentMissionId", currentMissionId);
}

public async Task<Robot> UpdateCurrentInspectionArea(string robotId, string? inspectionAreaId)
public async Task UpdateCurrentInspectionArea(string robotId, string? inspectionAreaId)
{
logger.LogInformation("Updating current inspection area for robot with Id {robotId} to inspection area with Id {areaId}", robotId, inspectionAreaId);
if (inspectionAreaId is null) { return await UpdateRobotProperty(robotId, "CurrentInspectionArea", null); }
if (inspectionAreaId is null)
{
await UpdateRobotProperty(robotId, "CurrentInspectionArea", null);
return;
}

var area = await deckService.ReadById(inspectionAreaId, readOnly: true);
if (area is null)
{
logger.LogError("Could not find inspection area '{InspectionAreaId}' setting robot '{IsarId}' inspection area to null", inspectionAreaId, robotId);
return await UpdateRobotProperty(robotId, "CurrentInspectionArea", null);
await UpdateRobotProperty(robotId, "CurrentInspectionArea", null);
}
else
{
await UpdateRobotProperty(robotId, "CurrentInspectionArea", area);
}
return await UpdateRobotProperty(robotId, "CurrentInspectionArea", area);
}

public async Task<Robot> UpdateDeprecated(string robotId, bool deprecated) { return await UpdateRobotProperty(robotId, "Deprecated", deprecated); }
public async Task UpdateDeprecated(string robotId, bool deprecated) { await UpdateRobotProperty(robotId, "Deprecated", deprecated); }

public async Task<Robot> UpdateMissionQueueFrozen(string robotId, bool missionQueueFrozen) { return await UpdateRobotProperty(robotId, "MissionQueueFrozen", missionQueueFrozen); }
public async Task UpdateMissionQueueFrozen(string robotId, bool missionQueueFrozen) { await UpdateRobotProperty(robotId, "MissionQueueFrozen", missionQueueFrozen); }

public async Task<Robot> UpdateFlotillaStatus(string robotId, RobotFlotillaStatus status)
public async Task UpdateFlotillaStatus(string robotId, RobotFlotillaStatus status)
{
var robot = await UpdateRobotProperty(robotId, "FlotillaStatus", status);
ThrowIfRobotIsNull(robot, robotId);
return robot;
await UpdateRobotProperty(robotId, "FlotillaStatus", status);
}

public async Task<IEnumerable<Robot>> ReadAll(bool readOnly = true) { return await GetRobotsWithSubModels(readOnly: readOnly).ToListAsync(); }
Expand All @@ -266,16 +258,15 @@ public async Task<IEnumerable<string>> ReadAllActivePlants(bool readOnly = true)
return await GetRobotsWithSubModels(readOnly: readOnly).Where(r => r.IsarConnected && r.CurrentInstallation != null).Select(r => r.CurrentInstallation!.InstallationCode).ToListAsync();
}

public async Task<Robot> Update(Robot robot)
public async Task Update(Robot robot)
{
if (robot.CurrentInspectionArea is not null) context.Entry(robot.CurrentInspectionArea).State = EntityState.Unchanged;
context.Entry(robot.Model).State = EntityState.Unchanged;

var entry = context.Update(robot);
context.Update(robot);
await ApplyDatabaseUpdate(robot.CurrentInstallation);
_ = signalRService.SendMessageAsync("Robot updated", robot?.CurrentInstallation, robot != null ? new RobotResponse(robot) : null);
DetachTracking(robot!);
return entry.Entity;
}

public async Task<Robot?> Delete(string id)
Expand Down Expand Up @@ -321,7 +312,7 @@ private IQueryable<Robot> GetRobotsWithSubModels(bool readOnly = true)
return readOnly ? query.AsNoTracking() : query.AsTracking();
}

private async Task<Robot> UpdateRobotProperty(string robotId, string propertyName, object? value, bool isLogLevelDebug = false)
private async Task UpdateRobotProperty(string robotId, string propertyName, object? value, bool isLogLevelDebug = false)
{
var robot = await ReadById(robotId, readOnly: false);
if (robot is null)
Expand All @@ -343,10 +334,9 @@ private async Task<Robot> UpdateRobotProperty(string robotId, string propertyNam
}
}

try { robot = await Update(robot); }
try { await Update(robot); }
catch (InvalidOperationException e) { logger.LogError(e, "Failed to update {robotName}", robot.Name); };
DetachTracking(robot);
return robot;
}

private async Task ApplyDatabaseUpdate(Installation? installation)
Expand Down

0 comments on commit 7996d46

Please sign in to comment.