SObjectizer-5.7.0 и so5extra-1.4.0
От: so5team https://stiffstream.com
Дата: 23.01.20 12:04
Оценка: 32 (6)
Вышли очередные версии библиотек SObjectizer и so5extra.

SObjectizer -- это один из немногих все еще живых и развивающихся "акторных фреймворков" для C++ (еще есть QP/C++, CAF: C++ Actor Framework и совсем молодой еще проект rotor). Краткий обзор SObjectizer-а можно найти в этой презентации или в этой довольно старой уже статье. Хотелось бы подчеркнуть, что SObjectizer поддерживает не только модель акторов, но еще и такие модели как Publish-Subscribe и Communicating Sequential Processes. А so5extra – это набор дополнительных полезных прибамбасов для SObjectizer-а (например, реализованные на базе Asio диспетчер с пулом нитей и env_infrastructures, дополнительные типы message box-ов, средства для реализации синхронного взаимодействия и т.д.)

Если в двух словах, то:

* SObjectizer-5.7 теперь позволяет использовать `send_case` в функции `select()`. Это делает SObjectizer-овский `select()` гораздо более похожим на `select` из Golang-а. Но это нововведение нарушило совместимость с предыдущей версией 5.6, т.к. теперь старая функция `case_` стала называться `receive_case`;
* в версии 5.7 устранен недочет в механизме доставки обернутых в конверты сообщений (т.е. enveloped messages) в случае использования `transfer_to_state()` и `suppress()` у агентов-получателей;
* код so5extra теперь распространяется под BSD-3-CLAUSE лицензией, что позволяет бесплатно использовать so5extra при разработке закрытого программного обеспечения. Предыдущие версии распространялись под двойной лицензией (GNU Affero GPL v.3 и коммерческой);
* в so5extra-1.4 реализованы mchain-ы фиксированной емкости для случаев, когда эта емкость известна на этапе компиляции.

Если же рассказывать более подробно, то основная фишка SObjectizer-5.7 -- это возможность использования `select()` для отсылки исходящих сообщений (по аналогии с тем, как это происходит в Golang-е). Так что теперь можно делать вот такие вещи:

using namespace so_5;

struct Greetings {
   std::string msg_;
};

// Попытка отослать сообщения в соответствующие каналы,
// но все операции должны уложиться в 250ms.
select(from_all().handle_n(3).total_time(250ms),
   send_case(chAlice,
      message_holder_t<Greetings>::make("Hello, Alice!"),
      []{ std::cout << "message sent to chAlice" << std::endl; }),
   send_case(chBob,
      message_holder_t<Greetings>::make("Hello, Bob!"),
      []{ std::cout << "message sent to chBob" << std::endl; }),
   send_case(chEve,
      message_holder_t<Greeting>::make("Hello, Eve!"),
      []{ std::cout << "message sent to chEve" << std::endl; }));


В одном `select()` можно использовать и `send_case()` и `receive_case()` вместе. Например, вот SObjectizer-овская версия вычисления чисел Фибоначчи из в отдельном рабочем потоке (по мотивам из Golang's tour):

using namespace std;
using namespace std::chrono_literals;
using namespace so_5;

struct quit {};

void fibonacci( mchain_t values_ch, mchain_t quit_ch )
{
   int x = 0, y = 1;
   mchain_select_result_t r;
   do
   {
      r = select(
         from_all().handle_n(1),
         // Отсылка сообщения типа 'int' со значением 'x' внутри.
         // Отсылка выполняется только когда values_ch готов для приема
         // новых исходящих сообщений.
         send_case( values_ch, message_holder_t<int>::make(x),
               [&x, &y] { // This block of code will be called after the send().
                  auto old_x = x;
                  x = y; y = old_x + y;
               } ),
         // Ожидание сообщения типа `quit` из канала quit_ch.
         receive_case( quit_ch, [](quit){} ) );
   }
   // Продолжаем операции пока что-то отсылается и ничего не прочитано.
   while( r.was_sent() && !r.was_handled() );
}

int main()
{
   wrapped_env_t sobj;

   thread fibonacci_thr;
   auto thr_joiner = auto_join( fibonacci_thr );

   // Канал для чисел Фибоначчи будет иметь ограниченный объем.
   auto values_ch = create_mchain( sobj, 1s, 1,
         mchain_props::memory_usage_t::preallocated,
         mchain_props::overflow_reaction_t::abort_app );

   auto quit_ch = create_mchain( sobj );
   auto ch_closer = auto_close_drop_content( values_ch, quit_ch );

   fibonacci_thr = thread{ fibonacci, values_ch, quit_ch };

   // Читаем первые 10 значений из values_ch.
   receive( from( values_ch ).handle_n( 10 ),
         // Отображаем каждое прочитанное значение.
         []( int v ) { cout << v << endl; } );

   send< quit >( quit_ch );
}


Полное описание нововведений версии 5.7.0 можно найти здесь.

Основное изменение в so5extra-1.4 -- это смена лицензии на BSD-3-CLAUSE. Поэтому теперь все множество дополнений к SObjectizer-у из so5extra могут бесплатно использоваться в разработке закрытого коммерческого ПО.

Единственное нововведение в so5extra-1.4 -- это реализация mchain для случая, когда максимальный объем mchain-а известен на этапе компиляции. Подобные mchain-ы зачастую используются в сценариях request-response, где ожидается всего одно ответное сообщение на запрос:

#include <so_5_extra/mchains/fixed_size.hpp>
#include <so_5/all.hpp>
...
using namespace so_5;

// Канал для получения ответного сообщения.
auto reply_ch = extra::mchains::fixed_size::create_mchain<1>(env,
   mchain_props::overflow_reaction_t::drop_newset);
// Отсылаем запрос.
send<SomeRequest>(target, ..., reply_ch, ...);
// Ждем и обрабатываем ответ.
receive(so_5::from(reply_ch).handle_n(1), [](const SomeReply & reply) { ... });


Надеюсь, что SObjectizer/so5extra кому-нибудь окажется полезен. Если есть вопросы, то спрашивайте, постараюсь ответить.

PS. Изначально SObjectizer/so5extra жили на SourceForge, потом перехали на BitBucket, но в связи с тем, что вскоре с BitBucket-а окончательно выпилят все Mercurial-репозитории, SO-5/so5extra теперь уже живут и развиваются только на GitHub-е.
Re: SObjectizer-5.7.1 и so5extra-1.4.1
От: so5team https://stiffstream.com
Дата: 22.06.20 09:57
Оценка:
Стали доступны новые версии библиотек SObjectizer и so5extra.

Полный список изменений в SObjectizer-5.7.1 можно найти здесь.
Из новых возможностей отдельно можно выделить лимиты для сообщений по умолчанию. Начиная с 5.7.1 если агенту нужно обрабатывать множество сообщений с одинаковыми лимитами, то описание этого лимита можно сделать лишь один раз:
class demo final : public so_5::agent_t
{
public:
   demo(context_t ctx)
      : so_5::agent_t{ctx
         + limit_then_drop<msg_A>(100u)
         + limit_then_abort<msg_B>(10u)
         // Этот лимит будет использован для всех остальных сообщений.
         + limit_then_drop<any_unspecified_message>(50u)
         }
   {}

   void so_define_agent() override
   {
      // Для сообщения msg_A будет использован явно заданный лимит.
      so_subscribe_self().event([](mhood_t<msg_A> cmd) {...});

      // Для сообщения msg_C лимит будет создан автоматически.
      so_subscribe_self().event([](mhood_t<msg_C> cmd) {...});
   }
};


В so5extra-1.4.1 добавлен новый диспетчер asio_one_thread. Этот диспетчер предназначен для ситуаций, когда на одной рабочей нити нужно собрать сразу несколько агентов, которые выполняют IO-операции посредством Asio. И когда важно, чтобы все эти IO-операции выполнялись на одной и той же рабочей нити.
Re: SObjectizer-5.7.0 и so5extra-1.4.0
От: SaZ  
Дата: 15.07.20 01:50
Оценка: 10 (1)
Здравствуйте, so5team, Вы писали:

S>...


Наконец дошли руки до SObjectizer для своего пет-проекта. Пока полёт отличный, но изучение идёт не так быстро, как хотелось бы. Но чем дальше, тем лучше. Мой технический стек на данный момент: Qt, SObjectizer, sqlite_orm, grpc, boost.
Из мелких пожеланий — выложить куда-нибудь онлайн сгенерированную документацию, чтобы самому не возиться с doxygen. Так же можно больше примеров в стиле best practice

Спасибо за вашу работу. Если замечу баги, то буду спрашивать на гитхабе или тут.
Отредактировано 15.07.2020 1:53 SaZ . Предыдущая версия .
Re[2]: SObjectizer-5.7.0 и so5extra-1.4.0
От: so5team https://stiffstream.com
Дата: 15.07.20 05:53
Оценка: 9 (1)
Здравствуйте, SaZ, Вы писали:

SaZ>Наконец дошли руки до SObjectizer для своего пет-проекта. Пока полёт отличный, но изучение идёт не так быстро, как хотелось бы. Но чем дальше, тем лучше.


Для изучения еще можно использовать нашу старую Wiki на SourceForge: https://sourceforge.net/p/sobjectizer/wiki/Basics/
Там есть целая серия статей SO-5.5 By Example. Правда, для ветки 5.5, для 5.6/5.7 не было ресурсов пока эту серию обновить и перенести на github.

SaZ>Из мелких пожеланий — выложить куда-нибудь онлайн сгенерированную документацию, чтобы самому не возиться с doxygen.


В онлайне документацию по API можно найти здесь: https://stiffstream.com/ru/docs.html, в частности по SO-5.7: https://stiffstream.com/en/docs/sobjectizer/so_5-7/

SaZ>Так же можно больше примеров в стиле best practice


Учтем. Постараемся, по крайней мере.

SaZ>Спасибо за вашу работу.


Спасибо за правильный выбор
Отредактировано 15.07.2020 6:46 so5team . Предыдущая версия .
Re: SObjectizer-5.7.0 и so5extra-1.4.0
От: SaZ  
Дата: 19.07.20 16:30
Оценка:
Здравствуйте, so5team, Вы писали:

S>...


Здравствуйте.

Пытаюсь отправить сигнал сам себе, что-то вроде
struct Proceed final: public so_5::signal_t{};
//...
so_5::send<Proceed>(*this); // this - агент

Получаю статический ассерт: message.hpp(543): error C2338: message class must be derived from the message_t.
Как правильно писать обработчики сигналов?
Отредактировано 19.07.2020 16:34 SaZ . Предыдущая версия .
Re[2]: SObjectizer-5.7.0 и so5extra-1.4.0
От: so5team https://stiffstream.com
Дата: 19.07.20 16:49
Оценка:
Здравствуйте, SaZ, Вы писали:

SaZ>Пытаюсь отправить сигнал сам себе, что-то вроде

SaZ>
SaZ>struct Proceed final: public so_5::signal_t{};
SaZ>//...
SaZ>so_5::send<Proceed>(*this); // this - агент
SaZ>

SaZ>Получаю статический ассерт: message.hpp(543): error C2338: message class must be derived from the message_t.
SaZ>Как правильно писать обработчики сигналов?

А ошибка диагностируется в месте отсылки сигнала или в месте подписки на сигнал?
Re[3]: SObjectizer-5.7.0 и so5extra-1.4.0
От: SaZ  
Дата: 19.07.20 16:52
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здравствуйте, SaZ, Вы писали:


SaZ>>Пытаюсь отправить сигнал сам себе, что-то вроде

SaZ>>
SaZ>>struct Proceed final: public so_5::signal_t{};
SaZ>>//...
SaZ>>so_5::send<Proceed>(*this); // this - агент
SaZ>>

SaZ>>Получаю статический ассерт: message.hpp(543): error C2338: message class must be derived from the message_t.
SaZ>>Как правильно писать обработчики сигналов?

S>А ошибка диагностируется в месте отсылки сигнала или в месте подписки на сигнал?


Диагностируется в месте отсылки, но пропадает, если я удаляю подписку на обработчик. Поэтому я подразумеваю, что что-то не так с обработчиком.
class myagent: ...
{
  void onSignal(const Proceed&); // при void onSignal(Proceed); чуть другая ошибка
...
  so_subscribe_self().event(&myagent::onSignal); // Если закомментировать, то ошибка пропадает, но сигнал идёт вникуда.
}


Если не разберёмся сейчас, то накидаю минимальный примерчик.
Re[4]: SObjectizer-5.7.0 и so5extra-1.4.0
От: so5team https://stiffstream.com
Дата: 19.07.20 16:57
Оценка: 2 (1) +1
Здравствуйте, SaZ, Вы писали:

SaZ>Диагностируется в месте отсылки, но пропадает, если я удаляю подписку на обработчик. Поэтому я подразумеваю, что что-то не так с обработчиком.

SaZ>
SaZ>class myagent: ...
SaZ>{
SaZ>  void onSignal(const Proceed&); // при void onSignal(Proceed); чуть другая ошибка
SaZ>...
SaZ>  so_subscribe_self().event(&myagent::onSignal); // Если закомментировать, то ошибка пропадает, но сигнал идёт вникуда.
SaZ>}
SaZ>


Тогда все правильно. Сигналы не переносят информации, поэтому нет экземпляра Proceed и, соответственно, нельзя иметь обработчик сигнала в формате void(const Proceed&). Обработчик для сигнала должен иметь формат void(mhood_t<Proceed>).
Re[5]: SObjectizer-5.7.0 и so5extra-1.4.0
От: SaZ  
Дата: 19.07.20 17:05
Оценка:
Здравствуйте, so5team, Вы писали:

S>Тогда все правильно. Сигналы не переносят информации, поэтому нет экземпляра Proceed и, соответственно, нельзя иметь обработчик сигнала в формате void(const Proceed&). Обработчик для сигнала должен иметь формат void(mhood_t<Proceed>).


Благодарю, помогло. Я ещё почитаю документацию/хабр, пока понимаю, что фундаментальных знаний не хватает.

Сейчас пытаюсь написать простейший микросервис и скрестить gRPC и SObjectizer.
Re: SObjectizer-5 десять лет
От: so5team https://stiffstream.com
Дата: 07.12.20 09:04
Оценка: 4 (1) +1
SObjectizer-5, анонсы релизов которого здесь время от времени публикуются, недавно исполнилось 10 лет.

Не смотря на то, что в последние года 2-3 темп развития SObjectizer-5 снизился, проект не заброшен, он живет. Недавно был выпущен корректирующий релиз для ветки 5.7.

Для тех, кто сталкивается с отсутствием приоритеной обработки сообщений в SObjectizer, может быть интересна эта статья. В ней рассказывается, как сделать доставку сообщений с учетом их приоритетов своими руками. Ну а если кто-то хочет видеть подобную функциональность сразу в SObjectizer-е, то дайте нам знать, пожалуйста. Можно будет предметно пообщаться и сделать то, что действительно кому-то нужно.
Re: Как выглядит код на SObjectizer в реальном проекте?
От: so5team https://stiffstream.com
Дата: 18.01.21 13:06
Оценка: 14 (3)
Мы рассказываем о SObjectizer уже давно. И сам SObjectizer снабжен большим количеством примеров.
Но вот о том, как выглядит реальный код, написанный для продакшена, у нас пока рассказать возможности не было.

Сейчас вот представилась. И по этому поводу была сделана статья: Проект arataga: реальный пример использования SObjectizer и RESTinio для работы с большим количеством HTTP-соединений.

Так что если кто-то задавался вопросом тянуть ли к себе в проект SObjectizer (и/или RESTinio), то теперь можно посмотреть и ужаснуться сделать собственные выводы.
Re: SObjectizer-5.7.3 и so5extra-1.5.0
От: so5team https://stiffstream.com
Дата: 11.01.22 06:03
Оценка: 6 (1) +1
Стали доступны новые версии библиотек SObjectizer и so5extra.

Принципиально нового в этих релизах нет, всего лишь представилась возможность реализовать некоторые накопившиеся по мере использования SObjectizer-а хотелки.

Подробнее об изменениях в SObjectizer можно прочитать здесь, а об изменениях в so5extra -- здесь.

В SObjectizer-5.7.3 хотелось бы выделить две новые фичи.

Во-первых, это возможность использовать собственные рабочие нити со штатными диспетчерами. Ранее штатные диспетчеры сами создавали экземпляры std::thread и как-то повлиять на это было нельзя. Теперь же можно сделать собственную фабрику рабочих нитей, к которой SObjectizer будет обращаться когда диспетчерам потребуются новые рабочие нити. Подробнее здесь.

Во-вторых, это новый метод `agent_t::so_deactivate_agent`, который переводит агента в специальное неактивное состояние и отменяет все подписки агента. Это может потребоваться когда в каком-то агенте возникла непоправимая ошибка и этот агент должен выключится из работы до тех пор, пока не будет дерегистрирована кооперация с этим агентом.

В so5extra-1.5.0 добавлен новый тип mbox-а: unique-subscribers. С одной стороны он похож на обычный Multi-Producer/Multi-Consumer mbox: сразу несколько агентов могут одновременно подписаться на него. Но, это Multi-Producer/Single-Consumer mbox. Все подписчики должны подписываться на разные типы сообщений. Это позволяет использовать unique-subscribers для публикации мутабельных сообщений не зная при этом, кто именно будет обрабатывать опубликованное сообщение. На обычных MPSC mbox-ах такого не сделать, т.к. при отсылке сообщения нужно знать конкретный MPSC mbox конкретного обработчика, а это не всегда удобно. Подробнее здесь.

PS. Важное послесловие к релизу от "того самого eao197".
Re: SObjectizer-5.7.4 и so5extra-1.5.1
От: so5team https://stiffstream.com
Дата: 18.05.22 08:55
Оценка: 6 (1)
Вышли очередные версии библиотек SObjectizer и so5extra.

Об изменениях можно прочитать здесь:

https://github.com/Stiffstream/sobjectizer/releases/tag/v.5.7.4
https://github.com/Stiffstream/so5extra/releases/tag/v.1.5.1

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

В общем, проект живет и продолжает развиваться.
Re: SObjectizer-5.7.0 и so5extra-1.4.0
От: A13x США  
Дата: 24.06.22 18:47
Оценка:
Здравствуйте, so5team, Вы писали:

S>Вышли очередные версии библиотек SObjectizer и so5extra.


>...


Есть ли пример подтягивания SObjectizer через FetchContent из cmake?
Был бы весьма благодарен, если бы кто-то поделился, если таковой пример существует.
Re[2]: SObjectizer-5.7.0 и so5extra-1.4.0
От: so5team https://stiffstream.com
Дата: 26.06.22 07:45
Оценка: 6 (1)
Здравствуйте, A13x, Вы писали:

A>Есть ли пример подтягивания SObjectizer через FetchContent из cmake?

A>Был бы весьма благодарен, если бы кто-то поделился, если таковой пример существует.

Вроде бы как-то так: https://github.com/Stiffstream/sobjectizer-fetchcontent-demo

Но там есть засада, с которой пока не понятно что делать: если компилировать SObjectizer как SharedLib, то .so-шка затем не копируется куда следует при выполнении cmake --build . --target install. Как это победить непонятно, если у кого-то есть соображения или подсказки, то поделитесь, плз, это может помочь.
Re[3]: SObjectizer-5.7.0 и so5extra-1.4.0
От: A13x США  
Дата: 27.06.22 04:09
Оценка:
Здравствуйте, so5team, Вы писали:

S>...


S>Вроде бы как-то так: https://github.com/Stiffstream/sobjectizer-fetchcontent-demo



Здорово, спасибо большое! Мне вполне достаточно статической версии, так что пример вполне подходит. Можно было бы немножко упростить инструкцию по сборке убрав ключи, которые, наверное, больше были бы важны для кастомной сборки, во всяком случае "стандартная" последовательность работает:

mkdir build
cd build
cmake ..
make

./hello_world/sample.so_5.hello_world


Но это мелочи, спасибо за пример
Re: so5extra-1.5.2
От: so5team https://stiffstream.com
Дата: 01.07.22 11:22
Оценка:
Недавно удалось добавить в сопутствующий проект so5extra еще несколько новых реализаций mbox-ов (почтовых ящиков) и зафиксировать очередную версию so5extra-1.5.2.

Взять ее можно с GitHub или же воспользоваться vcpkg или conan.

Для лучшего понимания того, что из себя представляет so5extra и что там есть была подготовлена обзорная статья.
Re: SObjectizer-5.8.0 и so5extra-1.6.0
От: so5team https://stiffstream.com
Дата: 18.07.23 08:58
Оценка: 6 (1)
Вышли очередные версии библиотек SObjectizer и so5extra.

Полный список изменений можно найти в Wiki:

https://github.com/Stiffstream/sobjectizer/wiki/v.5.8.0

https://github.com/Stiffstream/so5extra/wiki/v.1.6.0

Менее полный, но с большим погружением в отдельные моменты, обзор изменений сделан в свежей статье на Хабре.

Если же говорить в двух словах, то начата новая ветка 5.8, в которой пришлось пойти на слом совместимости с предыдущей веткой 5.7. Так что при переходе на SO-5.8 потребуется модифицировать исходники. Не получилось придумать способ внедрить новую функциональность не поломав совместимость

Для тех, кто не слышал про этот проект, вкратце:

SObjectizer – это один из «акторных фреймворков» для C++ (еще есть QP/C++, CAF: C++ Actor Framework и rotor). Краткий обзор SObjectizer-а можно найти в этой презентации или в этой статье. Кроме модели акторов SObjectizer поддерживает еще и такие модели как Publish-Subscribe и Communicating Sequential Processes. А so5extra – это набор дополнительных полезных прибамбасов для SObjectizer-а, которые не хотелось добавлять в сам SObjectizer.

В двух словах, SObjectizer, – это инструмент для упрощения разработки некоторых типов многопоточных приложений на C++.

-----

Новая версия уже доступна через vcpkg, добавление в conan пока задерживается, но надеюсь, что скоро она появится и там.
Re[2]: SObjectizer-5.8.0 и so5extra-1.6.0
От: vsb Казахстан  
Дата: 18.07.23 09:41
Оценка: +1
Здравствуйте, so5team, Вы писали:

S>Если же говорить в двух словах, то начата новая ветка 5.8, в которой пришлось пойти на слом совместимости с предыдущей веткой 5.7. Так что при переходе на SO-5.8 потребуется модифицировать исходники. Не получилось придумать способ внедрить новую функциональность не поломав совместимость


А почему не соблюдаете semver? Это же всем удобней. Сломанная совместимость это признак новой мажорной версии.
Re[3]: SObjectizer-5.8.0 и so5extra-1.6.0
От: so5team https://stiffstream.com
Дата: 18.07.23 09:54
Оценка: 9 (2)
Здравствуйте, vsb, Вы писали:

S>>Если же говорить в двух словах, то начата новая ветка 5.8, в которой пришлось пойти на слом совместимости с предыдущей веткой 5.7. Так что при переходе на SO-5.8 потребуется модифицировать исходники. Не получилось придумать способ внедрить новую функциональность не поломав совместимость


vsb>А почему не соблюдаете semver? Это же всем удобней. Сломанная совместимость это признак новой мажорной версии.


Сложный политкорректный ответ: мы разделяем потерю совместимости на два уровня:

1) версии библиотеки X настолько разные, что X_1 и X_2 можно использовать в одном исходном файле. Грубо говоря:

#include <x_1/stuff.hpp>
#include <x_2/stuff.hpp>

int main() {
  x_1::some_class x1;
  x_2::some_class x2;
  ...
}

В нашем случае при такой потере совместимости меняется первая цифра. Т.е. был SObjectizer-4, стал SObjectizer-5. Может быть лет через 10-15 будет SObjectizer-6.

2) версии библиотеки X не настолько разные, чтобы X_1 и X_2 можно было использовать в одном исходном файле. Например, в версии X_2 удалили что-то или поменяли формат какого-то метода. И если программисту нужно перескакивать с X_1 на X_2 и обратно, то придется делать это через #if-ы (вроде такого).

В данном случае слом совместимости произошел на уровне 2), поэтому первая цифра не меняется.




Простой политкорректный ответ: т.к. проекты SObjectizer-4 и SObjectizer-5, по большому счету можно рассматривать как сильно разные, то первую цифру версии можно трактовать как часть имени проекта. Поэтому SObjectizer-5.8.0 можно рассматривать как SObjectizer-5 версии 8.0. Т.о. восьмерка становится первой цифрой версии и semver как бы соблюдается.




Неполиткорректный ответ: semver, может быть, хорошо работает для приложений, но (на мой субъективный взгляд) откровенно дерьмово для библиотек. Обсуждение этого выходит за рамки топика.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.