RoadRunner интегрируется посредством добавления цикла с получением PSR-7 запроса, поверх обычного запуска приложения, примерно вот так:
Код воркера
<?php
use Spiral\Goridge\StreamRelay;
use Spiral\RoadRunner\Worker;
use Spiral\RoadRunner\PSR7Client;
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Illuminate\Http\Request;
require_once(__DIR__ . '/../vendor/autoload.php');
$relay = new StreamRelay(STDIN, STDOUT);
$psr7 = new PSR7Client(new Worker($relay));
$requester = new HttpFoundationFactory();
$responder = new DiactorosFactory();
$app = require_once(__DIR__ . '/../bootstrap/app.php');
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
while ($psr7Request = $psr7->acceptRequest()) {
try {
$request = Request::createFromBase(
$requester->createRequest($psr7Request)
);
$response = $kernel->handle($request);
$kernel->terminate($request, $response);
$psr7Response = $responder->createResponse($response);
$psr7->respond($psr7Response);
} catch (\Throwable $e) {
$psr7->getWorker()->error((string) $e);
}
}
При таком подходе, постоянно есть ссылка только на инстанс $app и $kernel. Все остальное, что находится вне этих инстансов, сборщик мусора затирает (ибо он затирает все, на что ссылок больше не осталось), в том числе и подключения к БД (если они созданы вне контейнера $app), сокеты и прочие ресурсы.
В теории, если внести создание $app и $kernel внутрь цикла, то сборщик мусора при каждом новом запросе будет чистить абсолютно все.
github.com/kelseyhightower/envconfig — так как вся конфигурация приложения делается через переменные среды, то очень полезная либа, чтобы поддерживать код чистым
Кроме того, у нас есть внутренние либы, которые мы переиспользуем от проекта к проекту: автогенерация структур и каркаса сервера по swagger-спецификации и фреймворк для функционального тестирования — уверен, что расскажем про них подробнее в отдельных статьях.
paymentMethod — это метод оплаты из ФФД 1.05. Звучит немного непонятно, но глядя на допустимые значения — всё становится ясно:
Возможные значения:
1 — Предоплата 100 %
2 — Предоплата
3 — Аванс
4 — Полный расчет
5 — Частичный расчет и кредит
6 — Передача в кредит
7 — Оплата кредита
Не следует путать с paymentType — это другое поле!
paymentObject — соответственно, тип позиции.
Возможные значения:
1 — Товар
2 — Подакцизный товар
3 — Работа
4 — Услуга
5 — Ставка азартной игры
6 — Выигрыш азартной игры
7 — Лотерейный билет
8 — Выигрыш лотереи
9 — Предоставление РИД (результатов интеллектульной деятельности)
10 — Платеж
11 — Агентское вознаграждение (в случае, когда вы обычный/банковский платежный агент/субагент, поверенный и т. д.)
12 — Составной предмет расчета
13 — Иной предмет расчета
То есть вполне возможны вариации, когда в одном чеке будут несколько позиций, одна из которых является, к примеру, товаром, и по нему был осуществлен полный расчет в момент передачи товара, вторая позиция — услуга, с предоплатой 100% (на момент регистрации оплаты услуга не была оказана), третья — вовсе услуга агента по приему платежа в пользу стороннего поставщика услуги, и т. д.
P. S. Точные значения, возможно, будут отличаться, в зависимости от модели ККТ «под капотом» сервиса
P. P. S. В случае если вы агент/субагент — всё становится ещё веселее, и появляется куча доп. реквизитов
Покопался в доках…
Адреса для rest и wsdl в 3dsec.sberbank.ru/payment ???
Да ладно, домен, судя по названию, выделенный для ACS, используется еще и для других целей? Как же они аудит по PCI DSS прошли?
Ну молодцы, движутся потихоньку в направлении Qubes OS
Ждем полную виртуализацию приложений и вкладок в браузере.
Вирусы навряд ли полностью исчезнут, но писать их будет уже существенно сложнее.
Насчет четвертого пункта: я стараюсь на проектах, где такое возможно, переводить режим бэкапов в Simple, чтобы минимально задействовались файлы логов. Это очень сильно оптимизирует нагрузку на диски.
Еще обязательно нужно выделять самый быстрый SSD под tempdb, и только под нее (хотя это зависит от характера базы и числа создаваемых временных таблиц, конечно). Держать рейд-массив из SSD под основные базы круто, но в моем случае нереально по бюджету, поэтому — на хранилище медленное, на темпдб — быстрое. Не так давно увидел пример, когда вынесение темпдб на ссд убрало дедлоки на основной базе, с которыми безуспешно вели борьбу годами.
Хорошая подборка! Даже немного жаль что в последнее время редко имею дело с разработкой БД. Подобные знания обычно добываются по крупицам.
Если возможно, было бы очень интересно знать ваше мнение об одном инструменте для MS SQL Server, который сделал для своих нужд. Код по ссылке. github.com/usharik/MsSqlDependencyBrowser
Как бы критиковать пост не хотел изначально. Но все же зачем так явно пиарить?
Из того с чем согласен… в этом туле нормальный форматтер, Intelligence и Index Manager. Схема компаратор сейчас сливает RedGate по скорости за счет частичного дескрайба в последнем + не всегда скрипты генерятся правильно (вместо ALTER часто таблица пересоздается — это актуально для 2014 версии сиквела). Дата компаратор хороший, но скрипты по синхронизации не всегда генерит оптимальные. Из-за чего работа в этом туле для админа на большой базе приятной явно не будет. Execution Plan хороший, но проигрывает во многом бесплатному PlanExplorer… скоро это в теории должно изменится с новым релизом. Производительность при работе с гридом где результаты запроса выводятся — это печаль надолго… из-за того что данные часто курсорами выгребаются из таблицы. InMemory, секционирование, компрессия и прочие интересные плюшкки поддержаны не полностью.
Итого получается, что для чего-то серьезного этот тул ИМХО не подойдет. Лично мне удобнее связка SSMS+SSDT+плагины.
Еще небольшое замечание, не очень хорошо что агент «дергает» процедуру достаточно часто раз в минуту, ведь ошибок может и не возникать весьма длительное время. Я бы воспользовался возможностями SQL Server Service Broker и в этом случае доставка сообщений будет действительно realtime и без участия SQL Server Agent.
Идея в следующем:
1. Создаем свой тип сообщения (CREATE MESSAGE TYPE)
2. Создаем контракт (CREATE CONTRACT)
3. Создаем процедуру для отправки сообщений
4. Создаем очередь (CREATE QUEUE), которая использует процедуру из п.3
5. Создаем службу (CREATE SERVICE), которая использует очередь из п.4 и контракт из п.3
Пример
-- активируем service broker
IF NOT EXISTS(SELECT * FROM master.sys.databases WHERE name = DB_NAME()
AND is_broker_enabled = 1)
BEGIN
DECLARE @sql nvarchar(max);
SET @sql = N'USE [master]; ALTER DATABASE [' + DB_NAME() + N'] SET NEW_BROKER; USE [' + DB_NAME() + '];';
EXECUTE(@sql)
SET @sql = N'USE [master]; ALTER DATABASE [' + DB_NAME() + N'] SET ENABLE_BROKER; USE [' + DB_NAME() + '];';
EXECUTE(@sql)
END;
GO
CREATE MESSAGE TYPE [http://tempuri.org/Notifications/SendErrorInfoEvent]
VALIDATION = WELL_FORMED_XML;
GO
CREATE CONTRACT [http://tempuri.org/Notifications/PostEventNotification]
(
[http://tempuri.org/Notifications/SendErrorInfoEvent] SENT BY ANY
);
GO
CREATE PROCEDURE [ProcessNotificationEvents]
AS
BEGIN
SET NOCOUNT ON;
DECLARE @message_body XML,
@message_type_name NVARCHAR(256),
@dialog UNIQUEIDENTIFIER ;
WHILE (1 = 1)
BEGIN
WAITFOR(
RECEIVE TOP(1)
@message_type_name = message_type_name,
@message_body = message_body,
@dialog = conversation_handle
FROM [EventNotificationQueue]
), TIMEOUT 2000;
IF @@ROWCOUNT = 0
BEGIN
BREAK;
END
IF (@message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')
BEGIN
END CONVERSATION @dialog ;
END
ELSE
BEGIN
/*
здесь реальный код обработки сообщения данные в @message_body
*/
RETURN 0
END
END
RETURN 0;
END
GO
CREATE QUEUE [EventNotificationQueue] WITH
STATUS = ON,
ACTIVATION (
STATUS = ON,
PROCEDURE_NAME = ProcessNotificationEvents,
MAX_QUEUE_READERS = 1,
EXECUTE AS OWNER
);
GO
CREATE SERVICE [http://tempuri.org/Notifications/EventNotificationService]
ON QUEUE [EventNotificationQueue]
(
[http://tempuri.org/Notifications/PostEventNotification]
);
GO
--
-- использование, можно оформить в виде процедуры
--
DECLARE @dialog UNIQUEIDENTIFIER;
BEGIN DIALOG CONVERSATION @dialog
FROM SERVICE [http://tempuri.org/Notifications/EventNotificationService]
TO SERVICE 'http://tempuri.org/Notifications/EventNotificationService'
ON CONTRACT [http://tempuri.org/Notifications/PostEventNotification]
WITH ENCRYPTION = OFF;
DECLARE @EventData XML;
-- формируем данные для отправки по электронной почте
SEND ON CONVERSATION @dialog
MESSAGE TYPE [http://tempuri.org/Notifications/SendErrorInfoEvent] (@EventData);
END CONVERSATION @dialog;
В коде могут быть неточности, но идея должны быть понятна.
IF (SELECT COUNT(*)
FROM sysjobs AS s
INNER JOIN sysjobsteps AS s2 (nolock) ON s2.job_id = s.job_id
INNER JOIN dbo.sysjobhistory sh (nolock) ON sh.instance_id=(SELECT MAX(sjh.instance_id) FROM dbo.sysjobhistory sjh (nolock) WHERE sjh.job_id=s.job_id AND sjh.step_id=s2.step_id)
AND sh.run_date>=(SELECT MAX(sjh.run_date) FROM dbo.sysjobhistory sjh (nolock) WHERE sjh.job_id=s.job_id AND sjh.step_id=0)
WHERE s.[enabled]=1 AND sh.run_status=0)>0
BEGIN
DECLARE @tableHTML AS NVARCHAR(max)
SET @tableHTML =
N'<H1>Ошибки в джобах на sql сервере '+@@SERVERNAME+'</H1>' +
N'<table border="1">' +
N'<tr><th>Джоб</th><th>ID шага</th>' +
N'<th>Имя шага</th><th>команда</th><th>база</th>' +
N'<th>последний запуск</th><th>ошибка</th></tr>' +
CAST ( ( SELECT td = s.name,'', td = s2.step_id,'', td = s2.step_name, '',td = cast(s2.command AS VARCHAR(100)),'', td = s2.database_name,'',
td = s2.last_run_date,'', td = cast(sh.[message] AS VARCHAR(100))
FROM sysjobs AS s (nolock)
INNER JOIN sysjobsteps AS s2 (nolock) ON s2.job_id = s.job_id
INNER JOIN dbo.sysjobhistory sh (nolock) ON sh.instance_id=(SELECT MAX(sjh.instance_id) FROM dbo.sysjobhistory sjh (nolock) WHERE sjh.job_id=s.job_id AND sjh.step_id=s2.step_id)
AND sh.run_date>=(SELECT MAX(sjh.run_date) FROM dbo.sysjobhistory sjh (nolock) WHERE sjh.job_id=s.job_id AND sjh.step_id=0)
WHERE s.[enabled]=1 AND sh.run_status=0
--ORDER BY s.name, s2.step_id
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;
DECLARE @subject AS NVARCHAR(max)
SET @subject='Ошибка в работе джобов на сервере '+@@SERVERNAME
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'MAIL'
,@recipients = ''
,@subject = @subject
,@importance ='Normal'
,@body = @tableHTML
,@body_format = 'HTML'
END
Из опыта, используем Zabbix для централизованного мониторинга. Количество заданий, выполнившихся с ошибкой мониторим через счетчик \SQLAgent:Jobs(_Total)\Failed jobs.
DECLARE @MINSIZE INT = 20; -- минимальное место на диске
DECLARE @RESULT VARCHAR(200) = '';
SELECT @RESULT = @RESULT + CASE
WHEN (available_bytes / 1024 / 1024 / 1024) > @MINSIZE
THEN ''
ELSE volume_mount_point + '=' + CAST(available_bytes / 1024 / 1024 / 1024 AS VARCHAR) + ' GB Free'
END + ' '
FROM sys.master_files AS f
CROSS APPLY sys.dm_os_volume_stats(f.database_id, f.file_id)
GROUP BY volume_mount_point, total_bytes, available_bytes;
SELECT CASE WHEN LTRIM(RTRIM(@RESULT))='' THEN 'OK' ELSE @RESULT END as RESULT
в итоге получаю результат в виде все «ОК» или список дисков, на которых место меньше порога указанного в @MINSIZE
Но мне лично Go не взошел
Очень уж специфичным показался
Но это только на мой взгляд!
Если их действительно можно будет объединить во что-то общее… Думаю, должна получиться как минимум Ракета_)
Все коннекты гарантированно упадут в какой-то момент если их не закрывать, больше нюансов расписано вот тут: https://github.com/spiral/roadrunner/wiki/Production-Usage
При таком подходе, постоянно есть ссылка только на инстанс $app и $kernel. Все остальное, что находится вне этих инстансов, сборщик мусора затирает (ибо он затирает все, на что ссылок больше не осталось), в том числе и подключения к БД (если они созданы вне контейнера $app), сокеты и прочие ресурсы.
В теории, если внести создание $app и $kernel внутрь цикла, то сборщик мусора при каждом новом запросе будет чистить абсолютно все.
Кроме того, у нас есть внутренние либы, которые мы переиспользуем от проекта к проекту: автогенерация структур и каркаса сервера по swagger-спецификации и фреймворк для функционального тестирования — уверен, что расскажем про них подробнее в отдельных статьях.
paymentMethod — это метод оплаты из ФФД 1.05. Звучит немного непонятно, но глядя на допустимые значения — всё становится ясно:
Возможные значения:
1 — Предоплата 100 %
2 — Предоплата
3 — Аванс
4 — Полный расчет
5 — Частичный расчет и кредит
6 — Передача в кредит
7 — Оплата кредита
Не следует путать с paymentType — это другое поле!
paymentObject — соответственно, тип позиции.
Возможные значения:
1 — Товар
2 — Подакцизный товар
3 — Работа
4 — Услуга
5 — Ставка азартной игры
6 — Выигрыш азартной игры
7 — Лотерейный билет
8 — Выигрыш лотереи
9 — Предоставление РИД (результатов интеллектульной деятельности)
10 — Платеж
11 — Агентское вознаграждение (в случае, когда вы обычный/банковский платежный агент/субагент, поверенный и т. д.)
12 — Составной предмет расчета
13 — Иной предмет расчета
То есть вполне возможны вариации, когда в одном чеке будут несколько позиций, одна из которых является, к примеру, товаром, и по нему был осуществлен полный расчет в момент передачи товара, вторая позиция — услуга, с предоплатой 100% (на момент регистрации оплаты услуга не была оказана), третья — вовсе услуга агента по приему платежа в пользу стороннего поставщика услуги, и т. д.
P. S. Точные значения, возможно, будут отличаться, в зависимости от модели ККТ «под капотом» сервиса
P. P. S. В случае если вы агент/субагент — всё становится ещё веселее, и появляется куча доп. реквизитов
Адреса для rest и wsdl в 3dsec.sberbank.ru/payment ???
Да ладно, домен, судя по названию, выделенный для ACS, используется еще и для других целей? Как же они аудит по PCI DSS прошли?
конкретный рецепт зависит от вашего сервера
Странно что на хабре на было новости о том что WinForms и WPF выложили в OpenSource.
Ждем полную виртуализацию приложений и вкладок в браузере.
Вирусы навряд ли полностью исчезнут, но писать их будет уже существенно сложнее.
Еще обязательно нужно выделять самый быстрый SSD под tempdb, и только под нее (хотя это зависит от характера базы и числа создаваемых временных таблиц, конечно). Держать рейд-массив из SSD под основные базы круто, но в моем случае нереально по бюджету, поэтому — на хранилище медленное, на темпдб — быстрое. Не так давно увидел пример, когда вынесение темпдб на ссд убрало дедлоки на основной базе, с которыми безуспешно вели борьбу годами.
Если возможно, было бы очень интересно знать ваше мнение об одном инструменте для MS SQL Server, который сделал для своих нужд. Код по ссылке.
github.com/usharik/MsSqlDependencyBrowser
Из того с чем согласен… в этом туле нормальный форматтер, Intelligence и Index Manager. Схема компаратор сейчас сливает RedGate по скорости за счет частичного дескрайба в последнем + не всегда скрипты генерятся правильно (вместо ALTER часто таблица пересоздается — это актуально для 2014 версии сиквела). Дата компаратор хороший, но скрипты по синхронизации не всегда генерит оптимальные. Из-за чего работа в этом туле для админа на большой базе приятной явно не будет. Execution Plan хороший, но проигрывает во многом бесплатному PlanExplorer… скоро это в теории должно изменится с новым релизом. Производительность при работе с гридом где результаты запроса выводятся — это печаль надолго… из-за того что данные часто курсорами выгребаются из таблицы. InMemory, секционирование, компрессия и прочие интересные плюшкки поддержаны не полностью.
Итого получается, что для чего-то серьезного этот тул ИМХО не подойдет. Лично мне удобнее связка SSMS+SSDT+плагины.
Идея в следующем:
1. Создаем свой тип сообщения (CREATE MESSAGE TYPE)
2. Создаем контракт (CREATE CONTRACT)
3. Создаем процедуру для отправки сообщений
4. Создаем очередь (CREATE QUEUE), которая использует процедуру из п.3
5. Создаем службу (CREATE SERVICE), которая использует очередь из п.4 и контракт из п.3
В коде могут быть неточности, но идея должны быть понятна.
подставив нужных получателей и почтовый профиль
в итоге получаю результат в виде все «ОК» или список дисков, на которых место меньше порога указанного в @MINSIZE