Что такое джоба в программировании
Перейти к содержимому

Что такое джоба в программировании

  • автор:

Job — шаблон проектирования для новичков и опытных Go программистов

Я начал программировать на Go после достаточно продолжительного периода программирования на PHP. Полагаю судя по последним тенденциям мой случай далеко не единичный. Go в целом набирает популярность среди Web разработчиков.

Итак, я в мире сусликов. А что делает прожженный до мозга костей PHP программист оказавшись там? Правильно, он продолжает «пыхтеть» — в силу своей профессиональной деформации — но уже на Go, со всеми вытекающими отсюда последствиями.

Признаюсь я никогда не был на собеседовании, устраиваясь на вакансию Go разработчика, но подозреваю, что там не задают вопросов про SOLID, Dependency Injection и различные прелести ООП. Там другой мир, другая парадигма (в целом разумеется не экстраординарная), связанная с параллельным программированием, строгой типизацией и отсутствием полноценного ООП в строгом его смысле — к тому ООП к которому мы привыкли по PHP, С++ или Java.

Поэтому в начале, разумеется, был определенный дискомфорт и ломка шаблонов. Я не понимал как использовать тот же context.Context, зачем он? Мои шаблоны готовы уже были треснуть, но матерого PHP программиста без хрена не съешь. Пора что-то с этим делать и писать свой велосипед! А именно то решение, которое мне, как PHP программисту, казалось достаточно очевидным для решения задача связанных с параллельным программирование, краеугольным камнем Go. Усевшись за рабочий ноутбук я почти месяц корпел над работой. Я хотел не просто сделать реализацию сферического коня в вакууме, а показать на конкретном примере возможность использования данного подхода. Так сказать, proof of concept. Ну и заодно набить руку на Go, чего греха таить.

После того как велосипед был готов, я выкатил его, осмотрел и, выдохнув, сказал сам себе: «ну, блин, вроде неплохо получилось. Нужно срочно рассказать об этом сообществу, пускай оценят«. Сказано — сделано. На Reddit была опубликована небольшая заметка про новый шаблон проектирования Go и, судя по реакции я понял… что люди ничего не поняли. «Зачем? Как это использовать? Так это же over-engineering» — в целом так можно охарактеризовать реакцию. Я не сдавался: «сейчас я вам нафотошоплю свой контраргумент. Ага, добавить это в README.md — пусть знают эти суслики«.

Как видят решение программисты

Как видят решение программисты

А если без шуток, то это, наверное, тема для отдельной статьи.

В целом о чем я? Много воды — ноль конкретики. Чтобы было реализовано:

Шаблон проектирования Job — это поведенческий шаблон проектирования, который инкапсулирует всю необходимую информацию для параллельного выполнения задач (task).

В качестве примера использования данного шаблона был реализован простой прокси-сервер, выполняющий роль балансировщика уровня L4; клиент, который сканируют указанную директорию на наличие изображений и отправляет все найденные изображения на backend сервер для изменения их размера; backend сервер, который обрабатывает запросы по изменению размера изображений. В основе всех трех приложений лежит компонент Job. Код так же доступен в репозитории на Github.

В целом сам шаблон Job — это аналог хорошо известного Command pattern, но с прицелом на параллельное выполнение. В той же статье есть конкретный пример его использования и для нашего случая:

Parallel Processing Where the commands are written as tasks to a shared resource and executed by many threads in parallel (possibly on remote machines; this variant is often referred to as the Master/Worker pattern)

Выполнение задач зависит друг от друга, если одна задача прерывает свое выполнение из-за ошибки — все остальные задачи останавливаются тоже. Все это, безусловно, можно реализовать с помощью context.Context, но реализация на более высоком уровне позволяет избавиться от рутинных действий, связанных с организацией параллельного выполнения задач и сконцентрироваться на реализации самой бизнес логики. Ну а сами ошибки очень легко отлавливать вызовами специальных методов вроде task.Assert заменяя ими более емкие конструкции if err != nil < panic(err) >.

Задачи разделяют данные и оркестрируют свое выполнение с помощью так называемой ping/pong синхронизации. Я приведу здесь лишь небольшой кускок кода, чтобы дать общее представление — полностью библиотека доступна в репозитории на Github по ссылке.

Это одна из задач клиента, которая обрабатывает приходящий ответ от сервера и сохраняет полученное изображение. Задача оркестирует свое выполнение — используя вышеупомянутую технику ping/pong синхронизации — с задачей, которая занимается файловым сканированием. Также она определяет, когда пришел последний ответ от сервера и когда нужно завершить выполнение всей работы (Job).

SQL Server jobs

In the day-to-day operations of running a business, employees can get caught up in more than one project, as is often the case.

We may be IT professionals but there is a limit to the amount of work that we can handle in one day and still stay on track.

With the amount of multitasking that employers feel their employees should be able to handle increasing with each passing day, the need to find a way to help themselves get the job done becomes increasingly more important.

Finding help and ways to get solutions into production even faster can make the day less stressful thereby making it more productive in the long run.

In the daily routine of a database administrator or a database developer, SQL Server has some functionality that can make life simpler and more dependable in the long run: SQL Server jobs.

How can the ability to create a job to handle routine tasks make the life of a database administrator or developer and how are SQL Server jobs created?

A SQL Server job is a collection of steps executed by the database engine by SQL Server Agent.

The job can perform many different functions within it that can save time and effort on the part of employees.

For example, a job can be created to import a daily update file internally or externally via an FTP server.

Another job can be configured to handle routine maintenance tasks as well as handling one-time production updates that may be needed in the future.

A job has many different options that can be configured during its creation in order to perform the duties that is needed of it.

In order to manage the jobs within a SQL Server database, use Enterprise Manager, and expand the Management node in Enterprise Manager.

Under the Management node is a node entitled SQL Server Agent. Expand this node and you will see the Jobs item that is used to represent the jobs within the system.

To see the jobs currently in the system, select Jobs. See the following illustration for an example of the steps described above:

SQL Server jobs

The window on the left will show the jobs currently in the system. This window displays a lot of information about the SQL Server jobs currently in the system that can prove valuable.

The first column lists the name of the job that was entered when it was created.

The second column lists the category of the job that was assigned at the time of the job’s creation. This helps to clarify the jobs and organize the jobs in the system.

The next column tells whether or not the job is enabled in the system.

If you wish to disable or enable a job in SQL Server, right click on the job and select on the Disable Job or Enable Job option from the popup menu.

The next column tells whether or not the job is runnable in the system.

After that there is a column, which tells whether or not the job is scheduled to run in the system.

The status column alerts the user to what is currently going on with the job. If the job is running it alerts the user to what step it is in currently.

The last run status column tells the status of the job’s last run and when that occurrence took place.

The final column shown tells when the next scheduled run is to take place.

To see the properties of a job in the window, right click on the job and select Properties from the popup menu or double click on the job. Either of these actions will bring up the following screen in order to set and/or view options contained in that job.

SQL Server jobs

The first tab (General) of this dialog shows the name of the job, when the job was created, whether or not the job is enabled, the category the job falls into, who owns the job within the database and a description of the job.

To disable a SQL Server job, uncheck the Enabled checkbox and the job will no longer run in the database if it was scheduled to do so.

The Steps tab of this dialog brings up the following screen:

SQL Server jobs

Each step within the job will be identified within this screen.

These steps can include executing data transformation packages, executing queries, executing stored procedures, etc.

Within this interface you can move the order of the steps around so that they occur in a specific order, as well as, add new steps or edit existing steps.

If you select a step and select the Edit button, the following screen appears:

SQL Server jobs

This screen is used to set the command that is to be executed during the current step.

You can also specify the name of the step, the type of command to execute and the exit code of the process if successful.

The tab also has a Schedule tab that can be used to manage the schedule of the SQL Server jobs.

This will allow the job to be set to occur once a daily, multiple times per day, weekly, monthly or just a one time. The job can be set to run at a certain times per day on a recurring basis as well, such as every hour or at a certain time per day.

The following screen shows the scheduling tab:

SQL Server jobs

To work with the schedule, click the New Schedule or the Edit button.

The New Schedule button will allow a new schedule to be input for the job.

The Edit button will allow the edit of the current schedule.

There is also a Notifications tab that can be used to handle notifications from the SQL Server in the event that something unusual occurs with the job while it is running.

The following screen shows the notification dialog which allows the selection of notifications options:

SQL Server jobs

Notifications can be sent in multiple methods. For the notification to work, there must be operators set up within SQL Server to receive them.

The notification can be an email, a page or a net send. Each notification can be used to alert the operator that something has occurred on the server and the actions are controlled by SQL Server Agent.

Once the SQL Server job is configured, the changes can be saved and the job can now be used to perform routine tasks on a regular basis which can free up resources within your organization.

Free eBook

What visitors say.

I have been in the database field for 10+ years and I have never before come across such a useful site. Thank you for taking the time to put this site together.»

Database Normalization eBook:

Database Normalization eBook

The name Oracle is a trademark of Oracle Corporation.
The names MS Access/MS SQL Server are trademarks of Microsoft Corporation.
Any other names used on this website may be trademarks of their respective owners, which I fully respect.

Заметки от Геннадия

«Job» , он же «джоб», он же «задание» — это отдельно стоящий кусочек кода; он независим от всех, как африканские племена независимы от системы центрального отопления. Похож на функцию, которая не пренадлежит ни одному классу. Предназначен для решения локальных задач разработчика (попробовать какой-то алгоритм, массово исправить данные, запорченные ошибкой в коде).
Далее я буду использовать термин «джоб».

Откройте дерево проектов и создайте новый проект «Blog45», и группу в нем (смотрите рисунок). У группы свойство «ProjectGroupType» должно быть равно «Jobs». Создание нового джоба Для создания нового джоба нажмите на правую кнопку мышки на узле «Jobs» и выберите пункт «Создать», «Job». Откроется редактор X++ с объявленным джобом. Переименуйте его в BLG45_Job и напишите код на рисунке ниже: Тело джоба BLG45_Job На рисунке выделены две кнопки: левая — сохранение изменений, правая — компиляция кода. Названия различные, суть одна: процессы сохранения и компиляции в Аксапте неотделимы («сохраняя, компилируем», «компилируя, сохраняем»).

В результате увидите белое окно с приветственным сообщением: Результат работы джоба

Блог Rouse_

Конечно же, это называется планирование, и самое первое, что приходит на ум — создать JOB, в который подключить дочерний процесс посредством вызова AssignProcessToJobObject.

Что есть JOB — по сути это достаточно удобный механизм позволяющий управлять множеством процессов, которые включены в него. У него есть много интересных фишек, но нас интересует только одна — надо закрыть все принадлежащие ему процессы как только JOB будет завершен.

Делается это достаточно просто:
У структуры TJobObjectExtendedLimitInformation, передаваемой на вход функции SetInformationJobObject, выставляем флаг JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, после чего все дочерние процессы запускаем с флагом CREATE_BREAKAWAY_FROM_JOB при вызове CreateProcess.

  1. создаем JOB вызовом CreateJobObject
  2. выставляем флаг закрытия всех дочерних процессов вызовом SetInformationJobObject
  3. запускаем дочерние процессы через CreateProcess
  4. каждый дочерний процесс подсоединяем к JOB вызовом AssignProcessToJobObject
  5. работаем как обычно

Но самое главное — если рутовый процесс держащий хэндл JOB-а прибьют через диспетчер задач, JOB все равно завершится, что и требовалось автору вопроса.

Впрочем, пожалуй хватит балаболить, давайте посмотрим на код.
В качестве дочернего процесса я выбрал штатный калькулятор, основное приложение будет запускать 4 его копии и, при завершении самого себя, будет их прибивать.

Для начала пишем обвес:

Тут просто декларация структур и API для работы с JOB, плюс процедура запуска калькулятора и аттача его к созданному ранее JOB-у RunCalcAndAttachToJob.
Пока не сильно вникайте в этот код, я на нем остановлюсь ниже.

А теперь посмотрим как будет выглядеть основное приложение:

Ага — это все.
Просто создаем JOB и подключаем к нему процессы калькуляторов.

А знаете как эта задача была решена в итоге?
Через создание удаленного потока, и не спрашивайте у меня: «почему это было сделано именно через него», не я автор вопроса и не я решал эту задачу 🙂

Вопрос номер 2:

Пробуем решить эту задачу через тот-же JOB.
Здесь задача немного усложняется, т.к. рутовых процессов может быть много, а дочерний — (support.exe) только один.

Решаем ее по стандартной схеме через наименование, а именно — у функции CreateJobObject вторым параметром идет имя задачи.
Зная это имя, второй процесс может открыть эту задачу и подключить самого себя к JOB-у посредством OpenJobObject и того-же AssignProcessToJobObject.

  1. если при старте мы не можем открыть задачу по ее имени — значит мы первые
  2. если мы первые — создаем задачу и подключаем к ней самого себя и калькулятор
  3. если вдруг такая задача уже существует — просто открываем ее и подключаем самого себя

Функция HaseJob проверяет наличие JOB и, будь таковой, подключает себя к нему.
Ну а если JOB не создан — создаем процесс калькулятор и аттачим его к JOB-у.

Проверьте — приложение main_app2 можно запустить сколько угодно раз, но калькулятор будет запущен только единожды и закроется только тогда, когда вы закроете самый последний экземпляр main_app2.

Немного комментариев по коду

Обратите внимание на выравнивание структур в модуле job_api.
Если структуры TIOCounters или TJobObjectExtendedLimitInformation будут неверно размещены в памяти — SetInformationJobObject выполнится не успешно.

Забудете флаг CREATE_BREAKAWAY_FROM_JOB — все это не заработает (см. MSDN).

Есть нюанс с консольками: если вы консоль и дочерние процессы тоже консоль — при закрытии консоли убьете всю кучу процессов. Надо как-то распределять дочерние процессы, к примеру через детач.

Писал все за вечер на Delphi7 и не проверял на юникодных вариантах Delphi (хард недавно умер — лень все переустанавливать), поэтому под юникодом не ручаюсь за правильность исполнения, но навскидку вроде ничего не пропустил и должно работать.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *