Смотрите видео ниже, чтобы узнать, как установить наш сайт в качестве веб-приложения на домашнем экране.
Примечание: Эта возможность может быть недоступна в некоторых браузерах.
Вы используете устаревший браузер. Этот и другие сайты могут отображаться в нём некорректно. Вам необходимо обновить браузер или попробовать использовать другой.
Подскажите, а как быть если шаблон нужно запускать с определенными входными настройками?
Как вариант я могу добавить несколько версий одного шаблона, но с разными шаблонами, получится в таком случае получить имя шаблона в ЗП (я могу например добавить template.xlmz, но назвать template1, template2)?
ZennoPoster.AddTask может создать несколько задач на один шаб.
Обязательные параметры:
Id, Name, IsNewbie, IsEnable, CreateTime, SettingsType
в ExecutionSettings: LimitOfThreads, MaxAllowOfThreads
в Project: ProjectFileLocation, ProjectType
CreateTime обязательно должен отличаться, иначе входные у задач будут одинаковые.
ProjectFileLocation - должен указывать на целевой шаб.
Либо, после запуска потока, загружать другие входные настройки.
Подскажите, а как быть если шаблон нужно запускать с определенными входными настройками?
Как вариант я могу добавить несколько версий одного шаблона, но с разными шаблонами, получится в таком случае получить имя шаблона в ЗП (я могу например добавить template.xlmz, но назвать template1, template2)?
Добавить в ZP шаблон (template.xmlz) и переименовать его в самом ZP (template1) (не файл), задать входные настройки.
Затем добавить ТОТ ЖЕ шаблон (template.xmlz) в ZP и опять его переименовать в ZP (template2) (не сам файл) и задать другие входные настройки и т.д.
Единственное что после изменения шаблона чаще всего слетают входные настройки, но их можно сохранить в файл и восстановить потом из файла, зато не нужно будет открывать шаблон заново после обновы, и все настройки от ZP прокси, расписание и т.д. останутся.
Входные настройки сохраняю как имя переименованного шаблона в ZP (template1.xml) рядом с файлом (template.xmlz).
Да, оказалось что один шаблон, добавленный несколько раз имеет разные айдишки.
Теперь пару вопросов:
1) А как стартовать шаблон? Допустим он на паузе, я добавил попыток, но как его запустить? StartTask метод?
2) Почему данный код не срабатывает, попытки не добавляются
C#:
string tempname = "Template";
if (OwnCode.CommonCode.TaskHelper.GetTaskId(tempname)==""){
project.SendErrorToLog("Не смогли найти проект "+tempname, true);
throw new Exception("Не найден проект");
} else {
project.SendInfoToLog(OwnCode.CommonCode.TaskHelper.GetTaskId(tempname));
ZennoPoster.AddTries(OwnCode.CommonCode.TaskHelper.GetTaskId(tempname), 50);
}
Хотя айдишка отлично парсится. В чем дело? Пробовал SetTries вместо AddTries, так же не работает.
3)Как-то можно количество успехов редактировать? - нашел, через SetExecutionSettings
А как можно получить изначальные настройки выполнения? - нашел, через GetTaskInfo
Очень интересна данная тема, хочу реализовать стек задач, то есть:
1-ый шаблон выполняет роль "диспетчера задач", который в свою очередь:
а) загружает таски из бд,
б) включает 2-ой шаблон, выставляет нужное кол-во потоков/выполненний.
Во 2-ом шаблоне главный процесс, запускает параллельные потоки, которые ждут сигнала от главного процесса (2-ого шаблона, своего рода менеджер аккаунтов/заданий). После чего распределяет таски (из 1-ого шаблона) по параллельным потокам (возможно через папки/файлы, пример: уникальное название папки token_session_task (генерирует уникальный номер сессии: ada123987AWDwd7, на время жизни 1 потока). Но по сути, жизнь 1 потока, не заканчивается по окончанию задачи, а ожидает от главного процесса новой инструкции. То есть, главный процесс контролирует статистику выполнения, по окончанию списка заданий, отправляет запрос на новую пачку заданий из 1-ого шаблона (диспетчер задач). Если заданий нет, то 1-ый шаблон глушит 2-ой (до поступления новых задач из центральной бд) или скидывает к минимальному кол-во потоков, к примеру 5 на 15 мин, если в течение этого времени из центральной бд не поступило заданий (их нет в бд), то глушится 2-ой шаблон, а первый шаблон продолжает чекать бд.
Вывод: По сути это стол заказов online, поступила задача, сразу выполняется, если нет, то работает на холостых.
П.С. Я новичок, еще многие алгоритмы и реализацию не познал, но заметил, что Lord_Alfred строил похожую логику.
Вопрос: На практике данный алгоритм актуальный для реализации или это костыль костыльный?
Не в замудренности дело Кому надо - тот разберется, а вот кому интересно, но не хватает знаний - не хватит желания дойти до конца и понять какой метод для чего использовать.
Именно поэтому в опен сорс проектах и делают документацию, чтоб повысить количество тех, кто будет использовать проект, ведь без пользователей - и смысла в опенсорсе нету)
П.С. Я новичок, еще многие алгоритмы и реализацию не познал, но заметил, что Lord_Alfred строил похожую логику, вопрос, на практике данных алгоритм актуальный или это костыл костыльный?
Я нахватал шишек с похожей логикой
Сейчас все шаблоны с похожими задачами делаю следующим образом: в MySQL храню в столбце "состояние" текущей строки и просто запускаю шаблон каждую минуту (через стандартные средства расписания в ZP), где внутри проверяю есть ли доступные задания. Иногда запускаю в работу не 1, а сразу 5-10 потоков.
Да, бывают ситуации, когда в базе накапливается больше строк для работы, чем добавляется потоков каждую минуту, но тут ничего не сделаешь. Ибо всё равно есть предел ресурсам, лучше их ограничивать по максимальному количеству потоков, а не запускать новый поток с каждым появившимся заданием.
Ну и такую логику гораздо проще дебажить + в случае ошибки внутри шаблона - менять статус в базе обратно.
Я нахватал шишек с похожей логикой
Сейчас все шаблоны с похожими задачами делаю следующим образом: в MySQL храню в столбце "состояние" текущей строки и просто запускаю шаблон каждую минуту (через стандартные средства расписания в ZP), где внутри проверяю есть ли доступные задания. Иногда запускаю в работу не 1, а сразу 5-10 потоков.
Да, бывают ситуации, когда в базе накапливается больше строк для работы, чем добавляется потоков каждую минуту, но тут ничего не сделаешь. Ибо всё равно есть предел ресурсам, лучше их ограничивать по максимальному количеству потоков, а не запускать новый поток с каждым появившимся заданием.
Ну и такую логику гораздо проще дебажить + в случае ошибки внутри шаблона - менять статус в базе обратно.
как вариант
На базе данного кода сделал контролер соединения, по сути пинговалку доступа в интернет.
Если нет ответа от сайта то ставим количество потоков ноль.
Часто задают вопросы, как запустить шаба из шаба, как управлять, добавить потоки итд.
Люди начинают создавать некошерные батники и прочими образами извращаться, хотя зенка предоставляет не очень приличный, но достаточный api для решения этих вопросов более адекватным путем.
Выкладываю небольшой статический класс упрощающий работу с запуском вторичных шабов.
Класс вставляем в общий код после
Код:
namespace ZennoLab.OwnCode
{
Код:
public static class TaskHelper
{
public static string GetTaskId(string TaskName)
{
var tasksList = ZennoPoster.TasksList;
foreach (var task in tasksList){
string tname = Regex.Match(task,@"(?<=<Name>).*?(?=</Name>)").Value;
string tid = Regex.Match(task,@"(?<=<Id>).*?(?=</Id><Name>)").Value;
if (tname == TaskName){
return tid;
}
}
return "";
}
public static int GetNumberOfTries(string TaskName)
{
string sid = TaskHelper.GetTaskId(TaskName);
var id = Guid.Parse(sid);
var taskInfo = ZennoPoster.GetTaskInfo(id);
string execsettings = Regex.Match(taskInfo,@"(?<=<ExecutionSettings>).*?(?=</ExecutionSettings>)").Value;
string ntries = Regex.Match(execsettings,@"(?<=<NumberOfTries>).*?(?=</NumberOfTries>)").Value;
int res=0;
Int32.TryParse(ntries,out res);
return res;
}
public static string GetStatus(string TaskName)
{
string sid = TaskHelper.GetTaskId(TaskName);
var id = Guid.Parse(sid);
var taskInfo = ZennoPoster.GetTaskInfo(id);
string status = Regex.Match(taskInfo,@"(?<=<Status>).*?(?=</Status>)").Value;
return status;
//Perform - работает
//Complite - завершен
//Stop - остановлен
//Schedule - запланирован
//WaitPerform - компилится
}
public static void WaitRun(IZennoPosterProjectModel project,string TaskName)
{
int nt = GetNumberOfTries(TaskName);
string status = GetStatus(TaskName);
while( nt >0 )
{
if(((ZennoLab.InterfacesLibrary.ProjectModel.Collections.IContextExt)project.Context).IsInterrupted) return; // Прерывание в ZP
if(Global.Variables.IsProjectMaker && !Global.Variables.IsDebugMode) return; // Прерывание в PM
Thread.Sleep(3000);
nt = TaskHelper.GetNumberOfTries(TaskName);
status = GetStatus(TaskName);
switch (status)
{
case "Perform":
break;
case "Complite": nt = 0;
break;
case "Stop": nt = 0;
break;
case "Schedule":
break;
case "WaitPerform":
break;
}
project.SendInfoToLog("Ожидаем завершения "+TaskName,true);
}
}
}
Примеры использования
Поиск айди шаблона по имени:
Код:
string tempname = "имя шаба";
if (TaskHelper.GetTaskId(tempname)==""){
project.SendErrorToLog("Не смогли найти проект "+tempname, true);
throw new Exception("Не найден проект");
}
Добавление нужного числа исполнений и ожидание завершения:
Код:
string tempname = "имя шаба";
int tries = 50; // будет добавлено 50 исполнений
if (tries>0){
ZennoPoster.AddTries(tempname , tries);
TaskHelper.WaitRun(project,tempname ); //ожидаем завершения всех исполнений
}
Да бывает такое.
Я из шаблона запускал парсер Орка на Гетах. В парсере еще делаю постинг в БД unixtime.
И в основном шабе брал этот unixtime и проверял сколько времени прошло с последнего обновления времени.
То WaitRun может получить неверное кол-во запущеных потоков, тк. AddTries их еще не запустило. Поэтому достаточно добавить паузу перед ожиданием и должно работать стабильно.
Код:
string tempname = "имя шаба";
int tries = 50; // будет добавлено 50 исполнений
if (tries>0){
ZennoPoster.AddTries(tempname , tries);
System.Threading.Thread.Sleep(1000);
TaskHelper.WaitRun(project,tempname ); //ожидаем завершения всех исполнений
}
Если потоки запущены и мы их прерываем, то никак нельзя узнать активные потоки.
TaskHelper.GetStatus показывает Stop TaskHelper.GetNumberOfTriesпоказывает 0
Хотя в проекте могут быть не завершенные потоки. На сколько мне известно нету метода который бы позволял получить активные потоки, может можно косвенно узнать о запущенных потоках?
Если потоки запущены и мы их прерываем, то никак нельзя узнать активные потоки.
Хотя в проекте могут быть не завершенные потоки. На сколько мне известно нету метода который бы позволял получить активные потоки, может можно косвенно узнать о запущенных потоках?
Создание/Уничтожение потока не быстрая операция. Созданные потоки похожи на бесконечный автоматы, если их отправить восвояси (не держа с ними связь на поводке, то они могут засесть в памяти), в то время, как главный поток уже закончил свою работу.
Все конечно индивидуально, но что-то да можно придумать...
Можно создать надстройку над пулом (ThreadPoolWorker), в котором есть свойства: Success, Completed и Exception.
Главный поток запускает метод:
C#:
public void Start(object state)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadExecution), state);
}
и ожидает асинхронной операции:
C#:
public void Wait()
{
while (Completed == false) //если операция не закончилась, ждать...
{
Thread.Sleep(100);
}
if(Exception != null) //если операция закончилась, проверить исключение...
{ //если возникло исключение, сделать проброс, чтобы отловить возникшую проблему...
throw Exception;
}
}
Метод обратного вызова:
C#:
private void ThreadExecution(object state)
{
try
{
action.Invoke(state);
Success = true; //закончилась успешно
}
catch (Exception ex)
{
Exception = ex; //записать тип исключения
Success = false; //закончилась неуспешно
}
finally
{
Completed = true; //асинхронная операция завершила свое выполнение
}
}
Реализовав диспетчер ожидания события или DispatcherTimer + CancellationTokenSource можно отменить операцию.
ThreadPool, минусы:
* Все потоки в пуле потоков являются фоновыми. В случае завершения работы всех приоритетных потоков в процессе работа всех фоновых потоков тоже останавливается. Сделать поток из пула приоритетным не удастся.
* Нельзя изменять приоритет или имя находящего в пуле потока. Все потоки в пуле представляют собой потоки многопоточного апартамента (multi-threaded apartment — МТА), а многие СОМ-объекты требуют использования потоков однопоточного апартамента (single-threaded apartment — STA).
* Потоки в пуле подходят для выполнения только коротких задач. Если необходимо, чтобы поток функционировал все время (как, например, поток средства проверки орфографии в Word), его следует создавать с помощью класса Thread.
* Нельзя создать поток с фиксированной идентичностью, чтобы можно было прерывать его или находить по имени.
Тогда на помощь class Thread или для более гибкой работы с потоками есть class Task, который может использовать так называемое продолжение (ContinueWith), ну и нововведение ValueTask.
2. Создание дополнительного потока, который выполняет основную логику кубика C#:
Предположим, необходимо вызвать метод:
C#:
private void DoSomething()
{ ... }
Отработка логики:
C#:
ThreadStart asyncMethod = new ThreadStart(DoSomething);
Thread thread = new Thread(asyncMethod);
thread.Start();
или реализовав оболочку для дополнительного потока, логика: Success, Completed, Exception и CancellationToken.
3. Завершение операции или отмена.
Главный поток ожидает завершение операции второго потока или ждет сигнал от диспетчера (ожидающий событие об отмене и оповещает главный поток о немедленном прекращение), а далее сохранение состояния второго потока.
Вроде похоже на правду и выглядит как, кучер с упряжкой лошадей, где все лошадки под контролем.
Доброго дня.
Во-первых, спасибо DmitryAk за тему и идею.
Когда набрел на тему — добавил туда свой метод, для получения даты следующего запуска нужных шаблонов работающих в планировщике:
C#:
/// <summary>
/// получаем дату следующего запуска
/// </summary>
/// <param name="TaskName"></param>
/// <returns></returns>
public static string NextSheduleDate(string TaskName)
{
string sid = TaskHelper.GetTaskId(TaskName);
var id = Guid.Parse(sid);
var taskInfo = ZennoPoster.GetTaskInfo(id);
string nextStartInfo = Regex.Match(taskInfo,@"(?<=<NextScheduleTime>).*?(?=</NextScheduleTime>)").Value;
return nextStartInfo;
}
И какое-то время юзал все это в нескольких шабах — строки с датами (в ZennoPoster.TasksList они представлены в формате MM/dd/yyyy hh:mm:ss) парсились в DateTime, все крутилось-вертелось. Потом шаблоны в которых это использовалось стали неактуальны, и я какое-то время не использовал фишку.
А сегодня понадобилось проверить состояние одного шаба (и получить дату его след. запуска) пред выполнением действий в другом. Ну дело-то не хитрое, закинул класс в общий код, накалякал такой кубик:
И приготовился почивать на лаврах, но...
В результате выполнения кубика в PM получил ошибку «Выполнение действия CSharp OwnCode. Строка не распознана как действительное значение DateTime.»
При этом строка вида string nextstart = "01/18/2021 23:17:22" по-прежнему замечательно парсится в DateTime через ParseExact, получение в строку значения из ZennoPoster.TasksList тоже происходит без ругани, даже пробовал через переменную проекта прогнать значение. На выходе все равно та же ошибка. PM перегружал, перебирал разные варианты CultureInfo — ничего не помогло.
В результате экспериментов я ошибку обошел таким образом:
C#:
CultureInfo provider = CultureInfo.InvariantCulture;
//Имя шаблона
string taskname = "TemplateName";
//Получили дату следующего запуска и разобрали ее на время и дату
string[] nextstart = TaskHelper.NextSheduleDate(taskname).Split(' ');
//получили DateTime
DateTime dttmpl = DateTime.ParseExact(nextstart[1],"T", provider);
Но! Вопрос остался — а что такого-эдакого присутствует в возвращаемой строке (реальный пример: 01/18/2021 23:17:28 ), точнее в ее части 01/18/2021, что приводит компилятор в замешательство? Или это только у меня PM выёживается?
Версия ZP 7.1.5, переходить на более свежие после просмотра веток с багами, пока не решался.
Дело в локалях. На разных серверах разные языки и их настройки, и .net это не просто учитывает, а применяет по умолчанию.
Единственное стоящее решение - настроить метод на универсальный парсинг.
В последних версиях постера, по умолчанию ru-ru или en-us в зависимости от языка постера, но это можно изменить:
Дело в локалях. На разных серверах разные языки и их настройки, и .net это не просто учитывает, а применяет по умолчанию.
Единственное стоящее решение - настроить метод на универсальный парсинг.
UPD. После перезагрузки системы заработали оба варианта. Ять, вечер выбросил на гребанные эксперименты!!!
P.S. А может это РКН своим блоком все починил )))
Дело в локалях. На разных серверах разные языки и их настройки, и .net это не просто учитывает, а применяет по умолчанию.
Единственное стоящее решение - настроить метод на универсальный парсинг.
В последних версиях постера, по умолчанию ru-ru или en-us в зависимости от языка постера, но это можно изменить: