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
<PackageReference Include="MyLab.Task.RuntimeSdk" Version="1.0.2" />
<PackageVersion Include="MyLab.Task.RuntimeSdk" Version="1.0.2" />
<PackageReference Include="MyLab.Task.RuntimeSdk" />
paket add MyLab.Task.RuntimeSdk --version 1.0.2
#r "nuget: MyLab.Task.RuntimeSdk, 1.0.2"
#:package MyLab.Task.RuntimeSdk@1.0.2
#addin nuget:?package=MyLab.Task.RuntimeSdk&version=1.0.2
#tool nuget:?package=MyLab.Task.RuntimeSdk&version=1.0.2
MyLab.Task.Runtime
MyLab.Task.Runtime - среда размещения и запуска задач.
Ознакомьтесь с последними изменениями в журнале изменений.
Обзор
MyLab.Task.Runtime (далее "Runtime") - сервис, обеспечивающий периодическое выполнение задач, реализованных в соответствии с MyLab.TaskRuntimeSdk (далее "SDK") на платформе .NET 5.0+.
При старте, Runtime загружает библиотеки с задачами (далее "ассеты") из директории ассетов. В этих ассетах находятся классы, реализующие интерфейс ITaskStartup(из SDK). В одном ассете можеет быть несколько таких классов. C помощью объектов этих классов создаются объекты, реализующие интерфейс ITaskLogic (из SDK), которые должны содержать логику конкретной задачи. При создании объекта задачи применяется персональная конфигурация для каждой задачи.
Созданные объекты логики задач сопоставляются с соответствующей конфигурацией и регистрируются в планировщике с указанным в конфигурации периодом запуска.
Ассет
Что такое Ассет?
Ассет - библиотека с зависимостями, содержащая набор классов, реализующих соответствующие интерфейсы из 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-requestsreceive-responsesremove-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 | Versions 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. |
-
net10.0
- Microsoft.Extensions.Configuration (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.