MyLab.Task.RuntimeSdk 1.0.2

dotnet add package MyLab.Task.RuntimeSdk --version 1.0.2
                    
NuGet\Install-Package MyLab.Task.RuntimeSdk -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MyLab.Task.RuntimeSdk" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MyLab.Task.RuntimeSdk" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="MyLab.Task.RuntimeSdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MyLab.Task.RuntimeSdk --version 1.0.2
                    
#r "nuget: MyLab.Task.RuntimeSdk, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MyLab.Task.RuntimeSdk@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MyLab.Task.RuntimeSdk&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=MyLab.Task.RuntimeSdk&version=1.0.2
                    
Install as a Cake Tool

MyLab.Task.Runtime

MyLab.Task.Runtime - среда размещения и запуска задач.

Ознакомьтесь с последними изменениями в журнале изменений.

SDK NuGet: NuGet

Обзор

MyLab.Task.Runtime (далее "Runtime") - сервис, обеспечивающий периодическое выполнение задач, реализованных в соответствии с MyLab.TaskRuntimeSdk (далее "SDK") на платформе .NET 5.0+.

При старте, Runtime загружает библиотеки с задачами (далее "ассеты") из директории ассетов. В этих ассетах находятся классы, реализующие интерфейс ITaskStartup(из SDK). В одном ассете можеет быть несколько таких классов. C помощью объектов этих классов создаются объекты, реализующие интерфейс ITaskLogic (из SDK), которые должны содержать логику конкретной задачи. При создании объекта задачи применяется персональная конфигурация для каждой задачи.

Созданные объекты логики задач сопоставляются с соответствующей конфигурацией и регистрируются в планировщике с указанным в конфигурации периодом запуска.

alternate text is missing from this package README image

Ассет

Что такое Ассет?

Ассет - библиотека с зависимостями, содержащая набор классов, реализующих соответствующие интерфейсы из SDK для реализации логики выполнения задач. Другими словами, с точки зрения разработчика задачи - это собранный проект, в котором реализованы классы логики задач и классы инициализации этих объектов логики.

ITaskStartup

Об интерфейсе ITaskStartup

Задача в ассете определяется классами, реализующими интерфейс ITaskStartup, далее "стартап". Требование к классам:

  • реализует интерфейс ITaskStartup;
  • публичный;
  • не абстрактный;
  • имеет конструктор по умолчанию.
О реализации ITaskStartup

Стартап должен реализовать такой же функционал, как класс Startup в веб-приложении - инициализацию приложения. Только в данном случае масштаб приложения сужается до задачи.

Ниже приведено объявление интерфейса стартапа.

/// <summary>
/// Initializes a task application
/// </summary>
public interface ITaskStartup
{
    /// <summary>
    /// Add custom configuration here
    /// </summary>
    void AddConfiguration(IConfigurationBuilder configBuilder);

    /// <summary>
    /// Add task logic and references here
    /// </summary>
    void AddServices(IServiceCollection services, IConfiguration configuration);
}

здесь:

  • AddConfiguration - в этом методе, при необходимости, следует указать дополнительные источники конфигурации;
  • AddServices - в этом методе следует добавить класс логики задачи, реализующей ITaskLogic, и его зависимости.

Логика задачи может быть зарегистрирована как с временем жизни Singletone, так и Scoped. Scoped - новый экземпляр на каждую итерацию.

Важно заметить, что добавление стартапом провайдеров логирования игнорируется. Используются настройки приложения.

ITaskLogic

Об интерфейсе ITaskLogic

Стартап должен добавлять в коллекцию сервисов логику задачи. Класс логики задачи должен реализовывать интерфейс ITaskLogic. Требования к классу логики:

  • реализует интерфейс ITaskLogic;
  • не абстрактный.

Ниже приведено объявление интерфейса логики задачи:

/// <summary>
/// Provides task logic
/// </summary>
public interface ITaskLogic
{
    /// <summary>
    /// Performs a logic
    /// </summary>
    ValueTask PerformAsync(TaskIterationContext iterationContext, CancellationToken cancellationToken);
}
Метод PerformAsync

Метод PerformAsync вызывается планировщиком в момент, когда пришло время выполнить задачу. Важно заметить, что если в этот момент предыдущая итерация задачи всё ещё выполняется, то метод вызван не будет.

Параметр iterationContext

Данный параметр содержит параметры контекста и позволяет сохранить данные для отчёта выполнения задача.

Ниже приведено описание класса контекста:

/// <summary>
/// Provides access to task logic iteration context  
/// </summary>
public class TaskIterationContext
{
    /// <summary>
    /// Trace identifier
    /// </summary>
    public string? TraceId { get; }
     /// <summary>
    /// Date and time of iteration start
    /// </summary>
    public DateTime StartAt { get; }
     /// <summary>
    /// Iteration report. 'null' by default.
    /// </summary>
    public IterationReport? Report { get; set; } = null;
}

Поля контекста:

  • TraceId - идентификатор трассировки, назначается уникальный для каждой итерации;

  • StartAt - содержит дату и время запуска текущей итерации;

  • Report - устанавливает отчёт о выполнении итерации задачи, который будет отправлен в протокол.

Отчёт итерации

По результатам выполнения итерации, при наличии необходимой конфигурации, Runtime отправляет запись в хранилище протоколов. Эту информацию можно дополнить прикладными данными, сформировав отчёт о выполнении итерации задачи и сохранить его в поле Report контекста итерации.

Ниже приведено объявление отчёта:

/// <summary>
/// Task iteration report
/// </summary>
public class IterationReport
{
    /// <summary>
    /// The identifier which correlate with task iteration
    /// </summary>
    public string? IterationId { get; set; }

    /// <summary>
    /// Gets or sets iteration workload
    /// </summary>
    public IterationWorkload Workload { get; set; }

    /// <summary>
    /// Gets or sets context subject identifier 
    /// </summary>
    public string? SubjectId { get; set; }

    /// <summary>
    /// Gets or sets business-level named numeric metrics
    /// </summary>
    public IDictionary<string, double>? Metrics { get; set; }
}

здесь:

  • InterationId - идентификатор итерации, если есть необходимость связать итерацию с каким-то конкретным идентификатором;
  • Workload - признак полезной работы итерации задачи:
    • Undefined - по умолчанию;
    • Idle - пустая итерация, не выполнившая полезную работу. Например, если выяснилось, что на данный момент ничего делать не нужно;
    • Useful - была выполнена полезная работа;
  • SubjectId - идентификатор субъекта, например пользователя, связанного с текущей итерацией задачи;
  • Metrics - именованные численные показатели итерации задачи. Например, сколько запросов отправлено.
Параметр cancellationToken

Передаёт токен отмены для прерывания выполнения задачи. Следует ориентироваться на этот токен при выполнении циклов и между этапами длительной работы.

Имя задачи

Имя задачи - уникальное строковое значение, идентифицирующее задачу. Образуется из имени ассета и имени задачи (при наличии), назначенного разработчиком.

Имя задачи используется:

  • в логах - автоматически добавляется в события, связанные с какой-либо задачей в метке task;
  • в протоколе - указывается в записях протокола об итерациях в поле type;
  • в конфигурации - чтобы указать персональную конфигурацию для задачи.

Имя задачи, указанное разработчиком называется локальным. Потому что локальное в пределах ассета. Оно должно быть уникальным в пределах ассета.

Локальное имя можно установить, с помощью атрибута TaskNameAttribute на классе стартапа:

[TaskName("foo")]
public class MyTaskStartup : ITaskStartup
{
    //...
}

Имя задачи, содержащее имя ассета и локальное имя называется квалифицированным и является уникальным для всех задач всех ассетов в одном Runtime экземпляре.

Квалифицированное имя задачи формируется по следующему шаблону:

{asset}:{local}

или при отсутствии локального имени задачи:

{asset}

Например, если ассет называется kolot-drova, и в нём есть единственная безымянная задача, то квалифицированное имя этой задачи будет kolot-drova.

Если такой ассет содержит именованные задачи, то их имена будут, например, такие:

drova:kolot
drova:zshech
drova:rostit

Рекомендуется использовать в качестве имён глаголы в нижнем регистре с дефисом-разделителем. Например:

  • send-requests
  • receive-responses
  • remove-old-files

Загрузка ассетов

Runtime при запуске загружает ассеты из директории ассетов. В этой директории должны располагаться поддиректории, содержащие библиотеки ассетов и их зависимости. Имена этих поддиректорий принимается за имя ассета. Библиотека ассета должна иметь такое же имя, как и директория.

Пример c ассетом drova:

> ls -1 /etc/task-runtime/assets
> drova

> ls -1 /etc/task-runtime/assets/drova
> drova.dll
> Reference1.dll
> Reference2.dll

Конфигурация

Состав конфигурации

Конфигурация приложения осуществляется стандартными средствами .NET и может быть установлена через файлы или переменные окружения.

Имя узла конфигурации приложения - Runtime.

Поля конфигурации:

  • AssetPath - путь к директории с ассетами. По умолчанию - /etc/task-runtime/assets;
  • ProtocolId - идентификатор протокола. tasks - по умолчанию;
  • BaseTaskConfig - общая часть конфигурации для всех задач. Опциональный параметр;
  • Tasks - персональные конфигурации задач. Опциональный параметр. Словарь, где ключ - квалифицированное имя задачи, а значение - объект конфигурации задачи, который содержит следующие поля:
    • Period - период выполнения задачи в формате, поддерживаемом парсингом класса TimeSpan;
    • Config - корень конфигурации задачи. Опциональный параметр.

Кроме того, для подключения протоколирования, потребуется указать конфигурацию для подключения к хранилищу протоколов. Подробнее в разделе Протокол.

Пример конфигурации с ассетом и задачей по умолчанию:

{
  "Runtime": {
    "Tasks": {
      "kolot-drova": {
        "Period": "00:01:00",
        "Config": {
          "Param1": "val1",
          "Param2": "val2"
        }
      }
    }
  }
}

Из-за формата квалифицированного имени, конфигурации задач одного ассета группируются. Например:

{
  "Runtime": {
    "Tasks": {
      "drova": {
        "kolot": {
          "Period": "00:01:00",
          "Config": {
            "Param1": "val1",
            "Param2": "val2"
          },
          "zshech": {
            "Period": "00:01:00",
            "Config": {
              "Param1": "val1",
              "Param2": "val2"
            }
          },
          "rostit": {
            "Period": "00:01:00",
            "Config": {
              "Param1": "val1",
              "Param2": "val2"
            }
          }
        }
      }
    }
  }
}

Конфиг задачи

При создании задачи используется сборная конфигурация, которая собирается следующими слоями, каждый следующий из которых может переопределять предыдущие:

  • узел Logging конфигурации приложения Runtime;
  • узел Runtime:BaseTaskConfig - общая часть конфигурации для всех задач;
  • узел Runtime:Tasks:[task-name]:Config;
  • добавление специфической конфигурации стартапа startup.AddConfiguration(...).

Запуск задач

Конкуренция

Runtime загружает и регистрирует для каждую задачу для одиночного запуска по расписанию. Это значит, что в одно и тоже время может выполняться только одна итерация задачи. Ограничений между задачами нет. Т.е. если планировщик задачи собрался выполнить задачу из-за того, что очередной период подошёл к концу, а в это время предыдущая итерация задачи ещё не закончена, то выполнение очередной итерации будет пропущено и перенесено на следующий период.

Задачи выполняются параллельно в пуле потоков. Выполнение задач асинхронное.

Трассировка

В приложении Runtime используются инструменты трассировки из OpenTelementry.

Для каждой итерации задачи устанавливается новая активность трассировки. В пределах выполнения задачи доступен текущий идентификатор трассировки как через контекст, так и через Activity.Current.TraceId.

Важно заметить, что идентификатор трассировки автоматически добавляется во все логи, написанные в пределах выполнения задачи. Также идентификатор трассировки автоматически добавляется во все исходящие HTTP запросы при условии использования IHttpClientFactory.

Протокол

Информация об итерациях задач может быть отправлена в хранилище протоколов.

Для активизации отправки событий в протокол, необходимо в конфигурации приложения Runtime указать адрес подключения:

{
  "Api": {
    "List": {
      "protocol-storage": { "Url": "http://foo-test.com" }
    }
  }
}

Идентификатор протокола указывается в конфигурации - Runtime:ProtocolId или значение по умолчанию.

Данные протокола формируются из служебных, определяемых Runtime-ом и прикладных, определяемых задачей через поле Report контекста итерации:

  • Специфицированные хранилищем:

    • id - идентификатор итерации, определяется полем IterationId из отчёта итерации задачи или идентификатором трассировки, если IterationId не указан;

    • datetime - дата и время начала итерации;

    • trace_id - идентификатор трассировки;

    • type - квалифицированное имя задачи;

    • subject - идентификатор субъекта, связанного с итерацией, из поля SubjectId отчёта итерации задачи;

  • Расширение:

    • workload - признак полезной нагрузки итерации, из поля Workload отчёта итерации задачи;
    • duration - длительность выполнения задачи;
    • error - описание неотловленного исключения итерации (формат);
    • metrics - именованные численные показатели выполнения итерации, из поля Metrics отчёта итерации задачи.

Развёртывание

docker-compose

В данном разделе приводится описание развёртывания на базе docker контейнеров.

Пример docker-compose файла для развёртывания Runtime сервиса:

version: 3.0

services:
	task-runtime:
		container_name: task-runtime
		image: ghcr.io/mylab-task/runtime:latest
		volume:
			./assets:/etc/task-runtime/assets

Предсборка

О предсборке

На момент запуска сервиса, ассеты должны уже присутствовать в директории ассетов. Один из вариантов развёртывания сервиса с задачами - использование предварительно сборанного docker-образа такого сервиса с установленными ассетами. В этом случае ассеты устанавливаются во время сборки образа.

Для этого необходимо создать образ на базе образа Runtime и добавить необходимые ассеты задач.

Ниже приведён Dockerfile с установкой ассета задач из tar файла, скачанного по ссылке:

FROM ghcr.io/mylab-task/runtime:latest

add-asset-tar.sh http://tar-url Test.Asset test

При сборке дочернего образа доступны скрипты для установки ассетов задач.

Скрипты предсборки
add-asset-tar

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

Параметры вызова:

add-asset-tar.sh URL LIB_NAME ASSET_NAME [AUTH_HEADER]
  • URL - адрес, по которому доступен файл TAR архива;
  • LIB_NAME - имя библиотеки-ассета. Без расширения ".dll";
  • ASSET_NAME - назначаемое имя ассета;
  • AUTH_HEADER - заголовок авторизации.

Пример вызова:

add-asset-tar.sh http://my-host/asset.tar TestAsset test "Authorzation: Bearer *****"
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 247 11/28/2025
1.0.1 422 11/7/2023