LINUX.ORG.RU

Ergo Framework 3.0

 ,


4

4

Ergo Framework – это реализация идей, технологий и шаблонов проектирования из мира Erlang на языке программирования Go. Он построен на акторной модели, сетевой прозрачности и наборе готовых компонентов для разработки. Это значительно упрощает создание сложных и распределенных решений, обеспечивая при этом высокий уровень надежности и производительности.

Эта версия знаменует собой важный этап в развитии Ergo Framework. Дизайн фреймворка был полностью переработан, и данная версия создана с нуля. Она включает:

  • Значительные улучшения API: интерфейсы Process, Node и Network были улучшены множеством удобных методов.
  • Новый сетевой стек: В этой версии представлен совершенно новый сетевой стек для улучшенной производительности и гибкости. Подробности можно найти здесь: https://github.com/ergo-services/benchmarks.

Вместе с выпуском Ergo Framework 3.0.0 также представлены новые инструменты и дополнительная библиотека компонентов:

Документация

Мы опубликовали исчерпывающую документацию по фреймворку, которая включает подробные руководства, помогающие эффективно использовать все возможности Ergo Framework. Она доступна на https://docs.ergo.services.

Поддержка Erlang

Начиная с версии 3.0.0, поддержка сетевого стека Erlang была перенесена в отдельный модуль и распространяется под лицензией BSL 1.1 - https://github.com/ergo-services/proto. Подробную информацию о использовании этого модуля можно найти в документации на https://docs.ergo.services/extra-library/network-protocols/erlang.

Быстрый старт

Для быстрого старта используйте инструмент ergo — утилиту командной строки, разработанную для упрощения процесса генерации шаблонного кода для вашего проекта на основе Ergo Framework.

Приятного кодинга✌️ https://ergo.services

>>> Подробности

★★★

Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 4)

Эх, так я и не дочитал книжку про Эрланг, всё другие дела отвлекают.

seiken ★★★★★
()
Ответ на: комментарий от ergo

но выводов уже наделано :) Конечно) Наш же мозг создан для оценочного суждения)

много «непонятно» должно было навести на мысль, что до написания выводов стоило бы немного внимательней поизучать.

Ну я прекрасно понимаю, что вам пришлось изобретать костыли чтобы сделать это все в рамках го

вполне стандартная практика. аллокация объекта, который реализует интерфейс.

Практика может и стандартная, но не значит правильная. Мы не реализуем интерфейсы в го. Смотрите, я сам когда-то писал такой код 100500 раз, то бишь делал такую саму ошибку, понадобилось время, чтобы осилить новую парадигму и начать мыслить в ней.

эта функция является аргументом для запуска процесса в методе Spawn.

Мне кажется это неправильным по той причине, что пользователь фреймворка тогда не контролирует цикл жизни обьекта. В жаве либо шарпе это очень распространено что цикл жизни управляется каким-то внешним фреймворком, например DI контейнером. В го принято делать наоборот. Может вместо фабрики (фабрика считается однако анти-паттерном) принимать один инстанс объекта, а не создавать новый каждый раз.

не буду углубляться в остальные «выводы». могу лишь пожелать больше усердия и внимательности в изучении. ну почитать все же документацию стоило, часть «выводов» с «непонятно» даже бы не появилась )

Ну вы тоже не обижайтесь) Лично я считаю что ваша имплементация акторов наверное лучшая, которую я видел для го, и вы все-таки проделали большую работу по его созданию, и ваше понимание концептов далеко выше среднего, наверное простите за мой тролльский тон, мы же на лоре, что вы ожидали?) Однако я считаю, что в имплементации есть концептуальные ошибки, которые я сам делал в прошлом.

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

эх, я когда-то вынужден был использовать akka.net и это было сложно, т.к. постоянно приходилось бороться с фреймворком, сама парадигма акторов ок и имеет право на существование. Просто в го у нас и так все аснхронное и легко паралелизируется, я не вижу какого-то принципиального бенефита от такого фреймворка. Может сетевая прозрачность является прикольной вещью и написанный монолит на акторах намного проще разбить, однако это редкая задача и все равно решается по-другому. Давайте представим ситуацию, что я невежественен и ничего не понимаю, но таких как я 100500 людей в мире, то вам так или иначе нужно продать идею, понимаете? Было бы очень прикольно и полезно, если бы вы описали цель создания фреймворка, какие проблемы он решает и более «приземленные» примеры. Например когда заходишь на сайт любого жс фреймворка, там всегда лендинг с красочным описанием почему конкретно тот самый лучший и офигенный.

да и п.7 вызывает вопросы в понимании го. без обид, но это прям слишком явно выглядит.

А какой именно вопрос вызывает?) Я понимаю, что встраивание пытаются использовать как наследование, однако это ним не есть и не для этого придумано) Я просто вижу вы мыслите в концепте ООП, а оно тут не работает.

nikolnik ★★★
()
Ответ на: комментарий от ergo

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

nikolnik ★★★
()
Ответ на: комментарий от Pwner

Надо понимать, ОС ты не используешь, пишешь свои маш. коды и сразу запускаешь на голом железе.

Ну тут все от ОС зависит. На самом деле ОС предоставляет низкоуровневые абстракции.

Выходит зря Пайку предъявляли, что Go не привносит ничего нового, ведь он придумал новую логику, логику Go.

Каждый язык привносит некоторую логику, парадигму, для его использования

Это что-то про то, что статуя уже в камне, нужно просто найти её.

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

А если не достаточно, то надо.

Конретно в приведенном примере они не нужны

Что можно делать? Снять трусы и бегать)

Ты точно хочешь донести до нас какую-то осмысленную идею, а не чувство, которое у тебя возникло при написании поста?

У меня какого-то специального чувства нет, о моих чувствах лучше не беспокойся)

Бредовым является твоё расстройство личности.

Кончились аргументы по-существу, раз пошел переход на личности?)

Если автор использует рефлексию/кодогенерацию, возврат интерфейсов – элегантное и простое решение.

Зачем возвращать интерфейс, если можно вернуть конкретный тип? Зачем нам рефлексия, если мы знаем типы в момент компиляции? Если у нас есть кодогенерация, в момент которой можно проверить все что нужно и сгенерировать конкретный код без рефлексии?

Как минимум, это позволяет получить бесплатное контекстое автодополнение в методах этой структуры.

А почему эти методы должны быть публичными в структуре? Можно просто было вместо встраивания передать как поле. А так получается у структуры актора все потроха наружу

Let me tell you about our lord and savior, convention.

То бишь мы должны создавать пустой метод, который ничего не делает, чтобы следовать какой-то конвенции?) Абсурд же.

nikolnik ★★★
()
Последнее исправление: nikolnik (всего исправлений: 2)
Ответ на: комментарий от nikolnik

но таких как я 100500 людей в мире, то вам так или иначе нужно продать идею

Суть в том, что я не продаю. Не подходит? Ок, не берите )

В п7 озвучена мысль, которая не коррелирует с пониманием как работает встраивание. Это не ООП, а возможность обеспечить пользовательский тип набором методов процесса. Плюс к этому, возможность сделать часть методов имплементации behaviour опциональными.

Так или иначе, у вас выводы бегут впереди понимания.

ergo ★★★
() автор топика
  1. Я считаю, что нужно отказаться от factory функций. Либо сам пользователь фреймворка должен конструировать объект и управлять его жизненным циклом, либо эти фактори-методы можно генерировать кодогенерацией. Заставлять пользователя их писать - это унылый бойлерплейт, всех это будет раздражать.

  2. Метод Init(…any) точно так себе решение. Фактически у нас дублируется конструктор (фактори) и второй конструктор в самом акторе. Пользователь должен сам конструировать объект актора, тогда от any можно избавиться. Использование any генерирует ошибки в рантайме. Го язык со строгой статической типизацией, потому пользователь фреймворка ожидает, что очень большой класс ошибок будут отлавливаться во время компиляции, а не в рантайме, иначе смысла от го нет, можно тогда на самом ерланге писать.

  3. context.Context, без него никуда, должен быть обязательным.

  4. «from gen.PID» - актор не должен знать, откуда приходит сообщение, для его работы это не должно как либо влиять на логику его работы. Можно на уровне фреймворка логгировать какой актор отправил сообщение и каким акторам оно пришло.

  5. По-любому message any плохое решение, наихудшее из возможных. В го нет алгебраических типов, потому в большой кодовой базе люди постоянно будут забывать обрабатывать новые сообщения. Здесь можно сделать два решения: Первое - создать структуру с перечислением всех сообщений, которые актор можно принимать

type Message1 struct {}
type Message2 struct {}
type Message3 struct {}

type MyActorMessages struct {
	Message1 *Message1
	Message2 *Message2
	Message3 *Message3
}

func (a *MyActor) HandleMessage(ctx context.Context, msg MyActorMessages) error {
 	switch {
	case msg.Message1 != nil:
		// logic 1
	case msg.Message2 != nil:
		// logic 2
	case msg.Message != nil:
		// logic 3
	default:
		panic("should not reach here"		
	}
}

Второe: создать метод для каждого отдельного сообщения, имхо это самое лучшее решение, этого легко достичь через кодогенерацию, рефлексия не будет нужна

type Message1 struct {}
type Message2 struct {}
type Message3 struct {}

type MyActorMessages struct {
	Message1 *Message1
	Message2 *Message2
	Message3 *Message3
}

func (a *MyActor) HandleMessage1(ctx context.Context, msg Message1) error {
}

func (a *MyActor) HandleMessage2(ctx context.Context, msg Message2) error {
}

func (a *MyActor) HandleMessage3(ctx context.Context, msg Message3) error {
}
  1. Нужно поизбавляться от обязательной имплементации пустых методов
// Start invoked once the application started
func (app *MyApp) Start(mode gen.ApplicationMode) {}

// Terminate invoked once the application stopped
func (app *MyApp) Terminate(reason error) {}

На уровне фреймворка во время composition root легко проверить существуют такие методы и опционально их вызывать

https://github.com/ergo-services/examples/blob/master/demo/apps/myapp/mytcp.go

Очень странно обрабатывается логика транспорта и запуска сервера, который выглядит как актор, хотя ним не является (?) Актор ничего не должен знать, какой транспорт для его сообщений должен использоваться. Нужно для фреймворка создать отдельную абстракцию «Transport» и он должен быть подключаем. Типа как сделано в пакете http, где есть интерфейс RoundTripper которым вообще можно замокать траспорт как таковой. В принципе ничего придумывать самому не надо, можно посмотреть как сделаны пакеты в стандартной либе го. Тут как-то сделано очень захардкожено.

  1. В примере https://github.com/ergo-services/examples/blob/master/call/actorA.go есть doCallLocal и doCallRemote

Актор должен просто отсылать какому-то актору сообщение, где находится destination actor, сам актор вообще знать не должен. Логика актора не должна вообще зависить куда физически нужно отправить сообщение. Здесь сам же автор идеи ломает принцип сетевой прозрачности. Очевидно, что в реальной жизни надо знать на какой ноде живет актор, но это должно конфигурироваться в composition root фреймворка, а не в самом акторе. Причем на уровне фреймворка нужно предусмотреть динамическое создание/удаление акторов прозрачно для других акторов. Да и в реальном приложении, сам процесс го будет крутиться в k8s. Даже на уровне сервиса мы можем не знать где физически другая нода и не знать ее адреса, потому это как-то должно происходить прозрачно. В идеале система акторов должна сделать k8s ненужным костылем, в такой конфигурации как сейчас это сделать не получится, нужно реально подумать над динамическим жизненным циклом нод, их топологии и service discovery.

  1. С помощью кодогенерации вы можете отказаться от ручного edf.RegisterTypeOf(MyRequest{}), это тоже легко сделать. Очевидно что пользователи будут постоянно забывать регистрировать типы и будут ловить ошибки в рантайме, от чего будут злиться и будут правы, ведь без использования фреймворка никакие типы регистрировать не надо будет и никаких ошибок в рантайме ловить не будут.

  2. Вместо встраивания act.Actor в актора, в го однако делают по-другому. Например можно посмотреть как сделали в пакете htpp. Вместо встраивания, просто передавайте это как аргумент в хендлере.

func (a *MyActor) HandleMessage1(ctx context.Context, actx act.Context, msg Message1) error {
actx.Send(...)
}
  1. Все-таки нужно достич того, чтобы объект актора был stateless. В самих полях актора хранить состояния нельзя.

  2. Все еще непонятно, как тестить акторы и систему что они все вместе разом работают как ожидается. В вашем фреймворке нужно еще сделать фреймворк для тестирования, фактически, типа как есть пакет httptest

  3. Любая асинхронная система основана на сообщениях звучит офигенно, пока не надо разобраться как действует уже какая-то существующая. Фреймворк мог бы генерировать диаграмму/граф который бы показывал какой актор куда какие сообщения отправляет и какие принимает. На самом деле, это тоже несложно сделать. Тогда ваш фреймворк был на расхват)

  4. В реальной распределенной системе еще нужно предусмотреть RateLimiter, Circuit Breaker и т.д, т.к. такую распределенную систему легко убить случайно высылая кучу сообщений и заддосить саму себя. Поверьте, это ошибка очень распространена и ее трудно предусмотреть.

  5. Фактически сейчас у вас очередь сообщений хранятся в памяти, в реальной жизни вы просто рискуете потерять данные, потому надо предусмотреть какое-то перзистен-хранилище для сообщений.

  6. Теоретически реальный кейс, если уже существует некая распределенная система с очередями, какой-нибудь sqs, kafka, gcp pub/sub, kafka, nats, rabbitmq, ваш фреймворк должен прозрачно использовать их как транспорт и уметь хендлить разные ситуации, например таймауты, acknowlege, commiting offset, буферизация в памяти и т.д., которые сделаны совершенно по-разному в каждом из них. Если бы вы придумали как это сделать, вас бы кормили омарами на каждой конференции.

nikolnik ★★★
()
Ответ на: комментарий от theNamelessOne

Да уж так с древних римлян пошло... Университетский устоявшийся латинский штамп :)

gns ★★★★★
()
Ответ на: комментарий от ergo

Суть в том, что я не продаю. Не подходит? Ок, не берите )

Вы сейчас озвучиваете очень инфантильную позицию, с такой жить очень сложно) выглядит так будто «я придумал такой офигенный фреймворк и такой суперовый патерн, а люди меня не понимают и только ругают плак-плак хнык-хнык». Да и что вы ожидали после публикования на лоре, если честно?)) Если бы опубликовали в го рассылке, то количество токсичных комментариев было бы 0, а здесь… ну сами знаете

nikolnik ★★★
()
Ответ на: комментарий от nikolnik

Дело в том, что я не реагирую на подобного рода «выводы». Они сделаны при полном отсутствии понимания предмета. Вы озвучиваете «как надо» даже не почитав документацию 😄. Как я писал выше, проект давно используется в продакшн у ряда компаний.

ergo ★★★
() автор топика
Ответ на: комментарий от nikolnik

Вы сейчас озвучиваете очень инфантильную позицию

Со стороны выглядит наоборот. Это вы тут уверены, что несете в массы единственно верную позицию того «как надо».

выглядит так будто «я придумал такой офигенный фреймворк и такой суперовый патерн, а люди меня не понимают и только ругают плак-плак хнык-хнык».

Выглядит так, как будто ув.тов.ergo сказал «я вот чего сделал, вот где лежит код, вот где лежит документация». А вы стараетесь доказать (неизвестно кому) как оно должно быть. Не могло бы быть, а именно должно быть. И если к вашим словам не прислушиваются, то исключительно из-за инфантильной позиции автора разработки.

Вот как-то это это выглядит со стороны.

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от eao197

Ему бесполезно что-то объяснять. Да и бессмысленно ибо он потратил столько времени на писанину «выводов» и поучений «как надо», а вот хотя бы документацию почитать времени не нашел :)

ergo ★★★
() автор топика

Кто пробудил древнее зло?

LamerOk ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.