Как узнать, какое задание завершено - PullRequest
0 голосов
/ 29 апреля 2019

У меня есть асинхронный код для загрузки всех файлов в каталоге в API.Он работает нормально, но я хотел бы отследить, какой файл был загружен и хотел бы войти, чтобы я мог выполнить некоторую проверку статуса.

Я следовал этому руководству , а также этот .Первая создает явные задачи для каждого файла, а вторая ссылка говорит только о количестве оставшихся задач.Я, с другой стороны, хотел бы выяснить, какое задание завершено, распечатать его в журнале и продолжить, пока не будет файлов для загрузки.Для этого я использую компонент «Сценарий» в SSIS.

Это когда две задачи определены специально для 2 файлов.

            Task<string> uploadCounterpartFileTask = UploadFiles(year, month, filename_counterparts, accesstoken, path);
            Task<string> uploadProductCategoryFileTask = UploadFiles(year, month, filename_productcategories, accesstoken, path);

            var allTasks = new List<System.Threading.Tasks.Task> { uploadCounterpartFileTask, uploadProductCategoryFileTask };


            while (allTasks.Any())
            {
                System.Threading.Tasks.Task finished = await System.Threading.Tasks.Task.WhenAny(allTasks);
                if (finished == uploadCounterpartFileTask)
                {
                    allTasks.Remove(uploadCounterpartFileTask);
                    var counterpartFile = await uploadCounterpartFileTask;
                }
                else if (finished == uploadProductCategoryFileTask)
                {
                    allTasks.Remove(uploadProductCategoryFileTask);
                    var productCategoriesFile = await uploadProductCategoryFileTask;
                }
            }

Но я не хочу делать это сейчас, так как яне будет знать, сколько файлов будет в каталоге

Я хотел бы загрузить все файлы в каталог, что-то вроде этого. :-

string[] fileSystemEntries = Directory.GetFileSystemEntries(path);

            var tasks = fileSystemEntries.OrderBy(s => s).Select(
            fileName => UploadFiles(year, month, Path.GetFileName(fileName), accesstoken, path));
            while (tasks.Any())
            {

                var finished = await System.Threading.Tasks.Task.WhenAny(tasks);



                    Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "File Uploaded" + finished.Result, string.Empty, 0, ref fireAgain);
                    tasks.Remove(finished);


            }
            Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "All Files Uploaded", string.Empty, 0, ref fireAgain);

Я использую готово. Результат, потому чтоВ документации MSDN указано, что Result дает задачу, которая была выполнена после whenAny.Я знаю, когда кто-нибудь дает первое, и поэтому я зацикливаюсь (аналогично примерам в MSDN).

Вы видите Dts.Events.FireInformation, поскольку это находится внутри задачи скрипта в SSIS.

Я ожидаю, что в журнале будет что-то вроде.

Загруженный файл: Counterparts.avro

Загруженный файл: ProductCategorties.avro

Загруженный файл: SomeOtherFile.avro

Все файлы загружены.

Но, хотя загрузка файла проходит нормально, ни одно из утверждений не печатается.

Как мне их напечатать?Я просто не хочу получать одно уведомление для всех файлов, мне бы очень хотелось, чтобы у меня был статус загруженного файла.

РЕДАКТИРОВАТЬ: В ответ на один из комментариев приведен код для UploadFiles.,В основном он загружает файл в API и для каждого файла вызывает 3 вызова REST.

    private async Task<string> UploadFiles(string year, string month, string filename, string accesstoken, string path)
    {
        //Initial Put
        var method = new HttpMethod("PUT");
        string url = String.Format("https://someurl/part1/{0}/{1}/{2}?resource=file&recursive=True", year, month, filename);


        var request = new HttpRequestMessage(method, url)
        {
            Content = null
        };

        request.Headers.Add("Authorization", "Bearer " + accesstoken);


        var initput = await client.SendAsync(request);

        //Append Data
        url = String.Format("https://someurl/part1/{0}/{1}/{2}?action=append&position=0", year, month, filename);

        string SourceFile = path;
        var content = new MultipartFormDataContent();
        string filenamefullyqualified = path + filename;
        Stream fs = System.IO.File.Open(filenamefullyqualified, FileMode.Open, FileAccess.Read, FileShare.None);
        content.Add(CreateFileContent(fs, filename, "text/plain"));

        method = new HttpMethod("PATCH");

        request = new HttpRequestMessage(method, url)
        {
            Content = content
        };

        //long filelength = new System.IO.FileInfo(filenamefullyqualified).Length;

        request.Headers.Add("Authorization", "Bearer " + accesstoken);

        var response = await client.SendAsync(request);

        long? position = request.Content.Headers.ContentLength;

        //Flush Data

        url = String.Format("https://someurl/part1/{0}/{1}/{2}?action=flush&position={3}", year, month, filename, position.ToString());

        request = new HttpRequestMessage(method, url)
        {
            Content = null
        };

        request.Headers.Add("Authorization", "Bearer " + accesstoken);


        response = await client.SendAsync(request);


        return filename;

    }

РЕДАКТИРОВАТЬ 2: В ответ на комментарий.Пожалуйста, обратите внимание, что это пример кода, который я пытаюсь продемонстрировать эту проблему.

    public async void Main()
    {
        bool fireAgain = true;
        HttpClientHandler httpClientHandler = new HttpClientHandler()
        {
            Proxy = new WebProxy("http://127.0.0.1:8888")
            {
                UseDefaultCredentials = true,
                BypassProxyOnLocal = true
            },
            UseDefaultCredentials = true
        };

        string year = "2019";
        string month = "02";
        string path = "D:\\SomeFolder\\AVRO\\";

        client = new HttpClient(handler: httpClientHandler, disposeHandler: true);
        string resp = getBearerToken().GetAwaiter().GetResult();
        var ser = new JavaScriptSerializer();
        var result = ser.DeserializeObject(resp);
        Dictionary<string, object> BearerTokenDetails = new Dictionary<string, object>();
        BearerTokenDetails = (Dictionary<string, object>)(result);

        string accesstoken = BearerTokenDetails["access_token"].ToString();
        Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "Access Code: " + accesstoken, string.Empty, 0, ref fireAgain);


        string[] fileSystemEntries = Directory.GetFileSystemEntries(path);

        var tasks = fileSystemEntries.OrderBy(s => s).Select(
        fileName => UploadFiles(year, month, Path.GetFileName(fileName), accesstoken, path));

        await System.Threading.Tasks.Task.WhenAll(tasks);
        Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "All Files Uploaded", string.Empty, 0, ref fireAgain);


    }

Вы увидите метод getBearerToken, который я определил как асинхронный, но позже сделал это вызовом Blocked с использованием GetResult, так как это необходимослучиться первым.Кроме того, обратите внимание: первый FireInfo, который вы видите после токена Bearer, сработал только после того, как я сделал блокирующий вызов (GetResult делает это, как я читал).

1 Ответ

0 голосов
/ 29 апреля 2019

Если FireInformation работает как задумано, ваш код может быть значительно упрощен.

Вы можете регистрировать завершение для задачи внутри UploadFiles:

private async Task<string> UploadFiles(string year, string month, string filename, string accesstoken, string path)
{
    // stuff


    response = await client.SendAsync(request);

    // Log task finished
    Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "File Uploaded" + filename, string.Empty, 0, ref fireAgain);  

    return filename;
}

Конец метода - это момент, когда файл был загружен и задача завершена. Нет необходимости в цикле while и ручном удалении задач из массива.

Кажется, вам даже больше не нужно возвращать имя файла, если это только для регистрации

Для записи всего завершенного сообщения просто напишите файл журнала после Task.WhenAll:

        string[] fileSystemEntries = Directory.GetFileSystemEntries(path);

        var tasks = fileSystemEntries.OrderBy(s => s).Select(
        fileName => UploadFiles(year, month, Path.GetFileName(fileName), accesstoken, path));

        await Task.WhenAll(tasks);
        Dts.Events.FireInformation(0, "Script Task for uploading AVRO files", "All Files Uploaded", string.Empty, 0, ref fireAgain);

Теперь, поскольку вы работаете в консоли, у вас есть две опции: используйте public async Task Main() в качестве сигнатуры метода (требуется c # 7.1, см. this ) или измените await Task.WhenAll(tasks); на Task.WaitAll(tasks); в противном случае приложение не будет ждать окончания работы вашего кода и, следовательно, ничего не выводится.

Дополнительно можно добавить строку Console.ReadKey(); в самом конце вашего Main метода и дождаться вывода результата.

...