Skip to content

Commit

Permalink
added progress for copy log data
Browse files Browse the repository at this point in the history
  • Loading branch information
vaclavbasniar committed Sep 26, 2023
1 parent e1b7c1e commit ce247d3
Show file tree
Hide file tree
Showing 17 changed files with 257 additions and 34 deletions.
2 changes: 2 additions & 0 deletions Src/WitsmlExplorer.Api/Configuration/Dependencies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public static void ConfigureDependencies(this IServiceCollection services, IConf
.IgnoreThisInterface<IWitsmlClientProvider>()
.IgnoreThisInterface<ICredentialsCache>()
.IgnoreThisInterface<IAsyncDisposable>()
.IgnoreThisInterface<IJobProgressService>()
.AsPublicImplementedInterfaces();
AddRepository<Server, Guid>(services, configuration);
services.AddSingleton<ICredentialsService, CredentialsService>();
Expand All @@ -39,6 +40,7 @@ public static void ConfigureDependencies(this IServiceCollection services, IConf
services.AddSingleton<IWitsmlSystemCredentials, WitsmlSystemCredentials>();
services.AddScoped<IWitsmlClientProvider, WitsmlClientProvider>();
services.AddSingleton<ICredentialsCache, CredentialsCache>();
services.AddTransient<IJobProgressService, JobProgressService>();
}

private static void AddRepository<TDocument, T>(IServiceCollection services, IConfiguration configuration) where TDocument : DbDocument<T>
Expand Down
2 changes: 2 additions & 0 deletions Src/WitsmlExplorer.Api/Jobs/JobInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public JobInfo()

public BaseReport Report { get; set; }

public int Progress { get; set; }

private JobStatus _status;

[JsonConverter(typeof(JsonStringEnumConverter))]
Expand Down
67 changes: 67 additions & 0 deletions Src/WitsmlExplorer.Api/Services/JobProgressService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;

using WitsmlExplorer.Api.Jobs;

namespace WitsmlExplorer.Api.Services
{
public interface IJobProgressService
{
void Setup(JobInfo jobInfo, double start = 0, double end = double.MaxValue);
void SetCurrent(double current);
}

public class JobProgressService : IJobProgressService
{
private JobInfo _jobInfo;
private double _start;
private double _end;
private double _current;

public void Setup(JobInfo jobInfo, double start = 0.0, double end = double.MaxValue)
{
if (jobInfo == null)
{
throw new InvalidOperationException("_jobInfo not set!");
}

_jobInfo = jobInfo;
_start = start < end ? start : end;
_end = end;
_current = _start;

UpdateJobProgress();
}

public void SetCurrent(double current)
{
if (_jobInfo != null)
{
if (current > _end)
{
_current = _end;
UpdateJobProgress();
}
else if (current > _current)
{
_current = current;
UpdateJobProgress();
}
}
}

private void UpdateJobProgress()
{
if (_jobInfo != null)
{
if (_start >= _end)
{
_jobInfo.Progress = 100;
}
else
{
_jobInfo.Progress = (int)Math.Floor((_current - _start) / (_end - _start) * 100.0);
}
}
}
}
}
75 changes: 55 additions & 20 deletions Src/WitsmlExplorer.Api/Workers/Copy/CopyLogDataWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ public interface ICopyLogDataWorker
public class CopyLogDataWorker : BaseWorker<CopyLogDataJob>, IWorker, ICopyLogDataWorker
{
private readonly IDocumentRepository<Server, Guid> _witsmlServerRepository;
private readonly IJobProgressService _jobProgressService;

public JobType JobType => JobType.CopyLogData;

public CopyLogDataWorker(IWitsmlClientProvider witsmlClientProvider, ILogger<CopyLogDataJob> logger = null, IDocumentRepository<Server, Guid> witsmlServerRepository = null) : base(witsmlClientProvider, logger)
public CopyLogDataWorker(IWitsmlClientProvider witsmlClientProvider, IJobProgressService jobProgressService, ILogger<CopyLogDataJob> logger = null, IDocumentRepository<Server, Guid> witsmlServerRepository = null)
: base(witsmlClientProvider, logger)
{
_witsmlServerRepository = witsmlServerRepository;
_jobProgressService = jobProgressService;
}

public override async Task<(WorkerResult, RefreshAction)> Execute(CopyLogDataJob job)
Expand Down Expand Up @@ -69,6 +73,8 @@ public CopyLogDataWorker(IWitsmlClientProvider witsmlClientProvider, ILogger<Cop
return (new WorkerResult(GetTargetWitsmlClientOrThrow().GetServerHostname(), false, errorMessage, e.Message), null);
}

SetupJobProgress(job, sourceLog);

int totalRowsCopied = 0;
int originalRows = 0;
if (existingMnemonicsInTarget.Any())
Expand Down Expand Up @@ -110,6 +116,17 @@ public CopyLogDataWorker(IWitsmlClientProvider witsmlClientProvider, ILogger<Cop
return (workerResult, refreshAction);
}

private void SetupJobProgress(CopyLogDataJob job, WitsmlLog sourceLog)
{
if (job.JobInfo != null && sourceLog.StartIndex != null && sourceLog.EndIndex != null)
{
double startIndex = StringHelpers.ToDouble(sourceLog.StartIndex.Value);
double endIndex = StringHelpers.ToDouble(sourceLog.EndIndex.Value);

_jobProgressService.Setup(job.JobInfo, startIndex, endIndex);
}
}

private static void SetIndexesOnSourceLogs(WitsmlLog sourceLog, CopyLogDataJob job)
{
if (!string.IsNullOrEmpty(job.StartIndex))
Expand Down Expand Up @@ -163,27 +180,10 @@ private async Task<CopyResult> CopyLogData(WitsmlLog sourceLog, WitsmlLog target
{
return await CopyLogDataWithoutDuplicates(sourceLog, targetLog, job, mnemonics, targetDepthLogDecimals);
}

int numberOfDataRowsCopied = 0;
await using LogDataReader logDataReader = new(GetSourceWitsmlClientOrThrow(), sourceLog, mnemonics, Logger);
WitsmlLogData sourceLogData = await logDataReader.GetNextBatch();
while (sourceLogData != null)
else
{
WitsmlLogs copyNewCurvesQuery = CreateCopyQuery(targetLog, sourceLogData);
QueryResult result = await RequestUtils.WithRetry(async () => await GetTargetWitsmlClientOrThrow().UpdateInStoreAsync(copyNewCurvesQuery), Logger);
if (result.IsSuccessful)
{
numberOfDataRowsCopied += sourceLogData.Data.Count;
}
else
{
Logger.LogError("Failed to copy log data. - {Description} - Current index: {StartIndex}", job.Description(), logDataReader.StartIndex);
return new CopyResult { Success = false, NumberOfRowsCopied = numberOfDataRowsCopied, ErrorReason = result.Reason };
}
sourceLogData = await logDataReader.GetNextBatch();
return await CopyLogData(sourceLog, targetLog, job, mnemonics);
}

return new CopyResult { Success = true, NumberOfRowsCopied = numberOfDataRowsCopied };
}

private async Task<CopyResult> CopyLogDataWithoutDuplicates(WitsmlLog sourceLog, WitsmlLog targetLog, CopyLogDataJob job, IReadOnlyCollection<string> mnemonics, int targetDepthLogDecimals)
Expand All @@ -192,6 +192,7 @@ private async Task<CopyResult> CopyLogDataWithoutDuplicates(WitsmlLog sourceLog,
double endIndex = StringHelpers.ToDouble(sourceLog.EndIndex.Value);
int numberOfDataRowsCopied = 0;
int originalNumberOfRows = 0;

do
{
WitsmlLogs query = LogQueries.GetLogContent(
Expand All @@ -201,7 +202,9 @@ private async Task<CopyResult> CopyLogDataWithoutDuplicates(WitsmlLog sourceLog,
sourceLog.IndexType, mnemonics,
Index.Start(sourceLog, startIndex.ToString(CultureInfo.InvariantCulture)),
Index.End(sourceLog, endIndex.ToString(CultureInfo.InvariantCulture)));

WitsmlLogs sourceData = await RequestUtils.WithRetry(async () => await GetSourceWitsmlClientOrThrow().GetFromStoreAsync(query, new OptionsIn(ReturnElements.DataOnly)), Logger);

if (!sourceData.Logs.Any())
{
break;
Expand All @@ -216,6 +219,7 @@ private async Task<CopyResult> CopyLogDataWithoutDuplicates(WitsmlLog sourceLog,
double firstSourceRowIndex = double.MinValue;
double lastSourceRowIndex = double.MinValue;
double targetIndex = double.MinValue;

foreach (WitsmlData row in data)
{
string[] split = row.Data.Split(",");
Expand All @@ -233,17 +237,21 @@ private async Task<CopyResult> CopyLogDataWithoutDuplicates(WitsmlLog sourceLog,
}
rowsToCollate.Add(split[1..]);
}

newData.Add(CollateData(rowsToCollate, targetIndex));
startIndex = lastSourceRowIndex >= endIndex ? endIndex : firstSourceRowIndex;

sourceLogWithData.LogData.Data = newData;

WitsmlLogs copyNewCurvesQuery = CreateCopyQuery(targetLog, sourceLogWithData.LogData);
QueryResult result = await RequestUtils.WithRetry(async () => await GetTargetWitsmlClientOrThrow().UpdateInStoreAsync(copyNewCurvesQuery), Logger);

if (result.IsSuccessful)
{
numberOfDataRowsCopied += newData.Count;
originalNumberOfRows += data.Count;

_jobProgressService.SetCurrent(startIndex);
}
else
{
Expand All @@ -255,6 +263,33 @@ private async Task<CopyResult> CopyLogDataWithoutDuplicates(WitsmlLog sourceLog,
return new CopyResult { Success = true, NumberOfRowsCopied = numberOfDataRowsCopied, OriginalNumberOfRows = originalNumberOfRows };
}

private async Task<CopyResult> CopyLogData(WitsmlLog sourceLog, WitsmlLog targetLog, CopyLogDataJob job, IReadOnlyCollection<string> mnemonics)
{
int numberOfDataRowsCopied = 0;
await using LogDataReader logDataReader = new(GetSourceWitsmlClientOrThrow(), sourceLog, mnemonics.ToList(), Logger);
WitsmlLogData sourceLogData = await logDataReader.GetNextBatch();

while (sourceLogData != null)
{
WitsmlLogs copyNewCurvesQuery = CreateCopyQuery(targetLog, sourceLogData);
QueryResult result = await RequestUtils.WithRetry(async () => await GetTargetWitsmlClientOrThrow().UpdateInStoreAsync(copyNewCurvesQuery), Logger);

if (result.IsSuccessful)
{
numberOfDataRowsCopied += sourceLogData.Data.Count;
}
else
{
Logger.LogError("Failed to copy log data. - {Description} - Current index: {StartIndex}", job.Description(), logDataReader.StartIndex);
return new CopyResult { Success = false, NumberOfRowsCopied = numberOfDataRowsCopied, ErrorReason = result.Reason };
}

sourceLogData = await logDataReader.GetNextBatch();
}

return new CopyResult { Success = true, NumberOfRowsCopied = numberOfDataRowsCopied };
}

private static WitsmlData CollateData(List<string[]> oldRows, double index)
{
string[] newRow = new string[oldRows.First().Length];
Expand Down
5 changes: 3 additions & 2 deletions Src/WitsmlExplorer.Api/Workers/Copy/CopyLogWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ public class CopyLogWorker : BaseWorker<CopyObjectsJob>, IWorker, ICopyLogWorker
private readonly ICopyLogDataWorker _copyLogDataWorker;
public JobType JobType => JobType.CopyLog;

public CopyLogWorker(ILogger<CopyObjectsJob> logger, IWitsmlClientProvider witsmlClientProvider, ICopyLogDataWorker copyLogDataWorker = null, IDocumentRepository<Server, Guid> witsmlServerRepository = null) : base(witsmlClientProvider, logger)
public CopyLogWorker(ILogger<CopyObjectsJob> logger, IWitsmlClientProvider witsmlClientProvider, IJobProgressService jobProgressService, ICopyLogDataWorker copyLogDataWorker = null, IDocumentRepository<Server, Guid> witsmlServerRepository = null)
: base(witsmlClientProvider, logger)
{
_copyLogDataWorker = copyLogDataWorker ?? new CopyLogDataWorker(witsmlClientProvider, null, witsmlServerRepository);
_copyLogDataWorker = copyLogDataWorker ?? new CopyLogDataWorker(witsmlClientProvider, jobProgressService, null, witsmlServerRepository);
}

public override async Task<(WorkerResult, RefreshAction)> Execute(CopyObjectsJob job)
Expand Down
1 change: 1 addition & 0 deletions Src/WitsmlExplorer.Frontend/__testUtils__/testUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export function getJobInfo(overrides?: Partial<JobInfo>): JobInfo {
startTime: "",
endTime: "",
killTime: "",
progress: 0,
status: "",
failedReason: "",
report: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styled from "styled-components";
import NavigationContext from "../../contexts/navigationContext";
import OperationContext from "../../contexts/operationContext";
import OperationType from "../../contexts/operationType";
import JobInfo from "../../models/jobs/jobInfo";
import JobInfo, { JobStatus } from "../../models/jobs/jobInfo";
import BaseReport from "../../models/reports/BaseReport";
import { Server } from "../../models/server";
import { adminRole, developerRole, getUserAppRoles, msalEnabled } from "../../msal/MsalAuthProvider";
Expand Down Expand Up @@ -107,6 +107,7 @@ export const JobsView = (): React.ReactElement => {
.map((jobInfo) => {
return {
...jobInfo,
status: jobInfo.status == JobStatus.Started.toString() && jobInfo.progress > 0 ? "Running (" + jobInfo.progress + "%)" : jobInfo.status,
failedReason: jobInfo.failedReason,
wellName: jobInfo.wellName,
wellboreName: jobInfo.wellboreName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TextField } from "@material-ui/core";
import React from "react";
import JobInfo from "../../models/jobs/jobInfo";
import JobInfo, { JobStatus } from "../../models/jobs/jobInfo";
import ModalDialog from "./ModalDialog";

export interface JobInfoPropertiesModalInterface {
Expand All @@ -19,7 +19,7 @@ const JobInfoPropertiesModal = (props: JobInfoPropertiesModalInterface): React.R
<TextField InputProps={{ readOnly: true }} id="id" label="Job ID" defaultValue={jobInfo.id} fullWidth />
<TextField InputProps={{ readOnly: true }} id="jobType" label="Job Type" defaultValue={jobInfo.jobType} fullWidth />
<TextField InputProps={{ readOnly: true }} id="status" label="Status" defaultValue={jobInfo.status} fullWidth />
{jobInfo.status == "Failed" && (
{jobInfo.status == JobStatus.Failed.toString() && (
<TextField InputProps={{ readOnly: true }} multiline id="failedReason" label="Failure Reason" defaultValue={jobInfo.failedReason} fullWidth />
)}
<TextField InputProps={{ readOnly: true }} id="objectName" label="Object Name(s)" defaultValue={jobInfo.objectName} fullWidth />
Expand Down
7 changes: 7 additions & 0 deletions Src/WitsmlExplorer.Frontend/models/jobs/jobInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ export default interface JobInfo {
endTime: string;
killTime: string;
status: string;
progress: number;
failedReason: string;
report: BaseReport;
}

export enum JobStatus {
Started = "Started",
Finished = "Finished",
Failed = "Failed"
}
Loading

0 comments on commit ce247d3

Please sign in to comment.