No soy fan de los diálogos de progreso. ¿Por qué? Creo que la mayoría mienten. 3 segundos para llegar al 98% y luego 10 minutos para el último 2%.

¿Qué? Podemos hacerlo mejor. Usemos el diálogo de progreso de Data Management de OneStream para realmente informar al usuario y decir la verdad sobre la tarea en ejecución.

Ya que estamos, también demos al usuario la posibilidad de cancelar una tarea en ejecución y hacer que esa tarea realmente se detenga.

Si ha creado cualquier tipo de proceso de Data Management de larga duración dentro de OneStream, del tipo que recorre meses o llama a sistemas externos, entonces seguramente ya pensó que sería útil proporcionar retroalimentación útil mientras se ejecuta.

Ahí es donde entra BRApi.TaskActivity.UpdateRunningTaskActivityAndCheckIfCanceled. Le permite enviar mensajes de estado al diálogo de Data Management y, igual de importante, comprobar si el usuario decidió cancelar el proceso.

El patrón básico es simple: llame a este método de forma periódica dentro de su código, pase un mensaje que describa lo que está haciendo y use el valor booleano true o false para decidir si debe salir.

No disfruto escribir nombres de funciones de más de 60 caracteres, enterrados varios objetos dentro de una librería.

Y BRApi.TaskActivity.UpdateRunningTaskActivityAndCheckIfCanceled es justo uno de esos casos feos. Solo necesita una API. Así que escribamos una. En este caso, es un simple método wrapper de una línea llamado UpdateDMDialog(message As String).

La función devuelve el mismo booleano que nuestra función de librería de más de 60 caracteres, indicando si el usuario hizo clic en cancelar. Entonces, si devuelve true, sé que el usuario canceló el proceso y también puedo salir de mi código. Eso les da a los usuarios una forma de detener el proceso sin matar el servidor ni esperar un timeout.

Vea el código de abajo para un ejemplo simulado y funcional de cómo usar BRApi.TaskActivity.UpdateRunningTaskActivityAndCheckIfCanceled.

El verdadero valor aquí está en los mensajes que envía. Piense menos en “30% completado” y más en “Obteniendo registros de mayo…” o “Esperando trabajo 12734 de NetSuite…”. Cualquier cosa que muestre qué está ocurriendo y en qué punto del proceso se encuentra le da confianza al usuario, o al menos una idea de si debería ir por un café o cancelar. Incluso puede incluir recuentos de registros, IDs de tareas o latencia de API si quiere ponerse elegante.

Uso este patrón en integraciones de datos, importaciones de archivos y prácticamente en cualquier lugar donde las cosas puedan tardar o fallar a mitad del proceso. Es liviano, le da control al usuario y es mucho mejor que dejarlos mirando un diálogo giratorio que engaña sobre el progreso real. Agregue algunas llamadas a UpdateDMDialog dentro de su loop y listo, usuario feliz e informado.

C#

public class DataImporter
{
    private readonly object si;
    private readonly object _args;
    private readonly string _dataType;
    private decimal _progress;

    public DataImporter(object sessionInfo, object args, string dataType)
    {
        si = sessionInfo;
        _args = args;
        _dataType = dataType;
        _progress = 0m;
    }

    private bool UpdateDMDialog(string message)
    {
        return BRApi.TaskActivity.UpdateRunningTaskActivityAndCheckIfCanceled(si, _args, message, _progress);
    }

    public async Task GetData(string yearInput)
    {
        var response = new List();
        long totalRecords = 0;

        UpdateDMDialog($"Starting {_dataType} import for year {yearInput}");

        for (int month = 1; month  r.ItemArray), Formatting.Indented);

        UpdateDMDialog($"All months complete. Total records: {totalRecords}");
        BRApi.ErrorLog.LogMessage(si, $"Preview:
{preview}");

        return table;
    }

    private Task Mock_DataRequestStart(string month)
        => Task.FromResult(Guid.NewGuid().ToString());

    private Task Mock_DataRequestStatus(string taskId)
        => Task.Delay(200);

    private Task Mock_DataRequestComplete(string month, string taskId)
        => Task.FromResult(new DataResult
        {
            Data = new List { "header", $"data for {month}" },
            RecordCount = 1
        });

    private DataTable Mock_ToDataTable(List rows)
    {
        var table = new DataTable();
        table.Columns.Add("Content", typeof(string));
        foreach (var row in rows)
            table.Rows.Add(row);
        return table;
    }

    private class DataResult
    {
        public List Data { get; set; }
        public long RecordCount { get; set; }
    }
}

VB.NET

Public Class DataImporter
    Private ReadOnly si As Object
    Private ReadOnly _args As Object
    Private ReadOnly _dataType As String
    Private _progress As Decimal

    Public Sub New(sessionInfo As Object, args As Object, dataType As String)
        Me.si = sessionInfo
        Me._args = args
        Me._dataType = dataType
        Me._progress = 0D
    End Sub

    Private Function UpdateDMDialog(message As String) As Boolean
        Return BRApi.TaskActivity.UpdateRunningTaskActivityAndCheckIfCanceled(si, _args, message, _progress)
    End Function

    Public Async Function GetData(yearInput As String) As Task(Of DataTable)
        Dim response As New List(Of String)()
        Dim totalRecords As Long = 0

        UpdateDMDialog($"Starting {_dataType} import for year {yearInput}")

        For month As Integer = 1 To 12
            Dim monthStr As String = $"{yearInput}-{month:D2}"
            UpdateDMDialog($"Starting {monthStr}...")

            Dim taskId As String = Await Mock_DataRequestStart(monthStr)
            Await Mock_DataRequestStatus(taskId)

            Dim result As DataResult = Await Mock_DataRequestComplete(monthStr, taskId)

            _progress = month * 8.33D
            UpdateDMDialog($"Finished {monthStr} - {result.RecordCount} records")

            If result.Data IsNot Nothing Then
                If response.Count = 0 Then
                    response.AddRange(result.Data)
                Else
                    response.AddRange(result.Data.Skip(1))
                End If

                totalRecords += result.RecordCount
            End If

            If UpdateDMDialog($"Imported {monthStr}") Then
                Return New DataTable()
            End If
        Next

        Dim table As DataTable = Mock_ToDataTable(response)
        Dim preview As String = JsonConvert.SerializeObject(
            table.AsEnumerable().Take(5).Select(Function(r) r.ItemArray),
            Formatting.Indented
        )

        UpdateDMDialog($"All months complete. Total records: {totalRecords}")
        BRApi.ErrorLog.LogMessage(si, $"Preview:{vbLf}{preview}")

        Return table
    End Function

    Private Function Mock_DataRequestStart(month As String) As Task(Of String)
        Return Task.FromResult(Guid.NewGuid().ToString())
    End Function

    Private Function Mock_DataRequestStatus(taskId As String) As Task
        Return Task.Delay(200)
    End Function

    Private Function Mock_DataRequestComplete(month As String, taskId As String) As Task(Of DataResult)
        Dim result As New DataResult With {
            .Data = New List(Of String) From {"header", $"data for {month}"},
            .RecordCount = 1
        }
        Return Task.FromResult(result)
    End Function

    Private Function Mock_ToDataTable(rows As List(Of String)) As DataTable
        Dim table As New DataTable()
        table.Columns.Add("Content", GetType(String))
        For Each row As String In rows
            table.Rows.Add(row)
        Next
        Return table
    End Function

    Private Class DataResult
        Public Property Data As List(Of String)
        Public Property RecordCount As Long
    End Class
End Class

Contacto

MindStream Analytics

¿Quiere saber más sobre OneStream Software? Complete el siguiente formulario y nos pondremos en contacto con usted en breve.