Предотвращение утечек памяти с помощью Comaged в совокупности, которая не создает событие - PullRequest
0 голосов
/ 11 декабря 2018

Приложению, созданному с Comaged 0.17.2 на Elixir 1.7.4, часто не хватает памяти.Исследование показало, что утечка памяти, по-видимому, вызвана растущим числом экземпляров агрегатов, которые никогда не останавливаются.

Рассматриваемый агрегат получает команды, запускаемые внешней системой.В некоторых случаях функция execute возвращает событие, а в некоторых других случаях команда должна игнорироваться и поэтому возвращает nil (как описано в docs ).

def execute(%RemoteThing{}, %ImportRemoteThing{deleted: true}), do: nil

Кажется, что каждый раз, когда возвращается nil, а не событие, агрегатный экземпляр сохраняется живым неопределенно долго.Это происходит, несмотря на то, что привязаны тайм-аут и срок жизни, что явно подразумевает что-то еще:

defmodule RemoteThing.Lifespan do
  @behaviour Commanded.Aggregates.AggregateLifespan

  def after_event(_event), do: :stop
  def after_command(_command), do: :stop
end

dispatch(
  ImportRemoteThing,
  to: RemoteThing,
  lifespan: RemoteThing.Lifespan,
  timeout: 15_000
)

Я подозреваю, что это ошибка в Comaged :

defp aggregate_lifespan_timeout(_context, []), do: :infinity

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

Сейчас я ищу способ остановить агрегатный экземпляр в случае, если execute функция возвращает nil.Любая идея обходного пути будет принята с благодарностью.

1 Ответ

0 голосов
/ 11 декабря 2018

Это уже исправлено и будет доступно в следующем выпуске Comaged .

Запрос на получение # 210 расширенное поведение совокупной продолжительности жизни, включающее after_error/1и after_command/1 callbacks.

Ранее вам нужно было только определить функцию after_event/1 callback для реализации поведения Commanded.Aggregates.AggregateLifespan:

defmodule BankAccountLifespan do
  @behaviour Commanded.Aggregates.AggregateLifespan

  def after_event(%BankAccountClosed{}), do: :stop
  def after_event(_event), do: :infinity
end

Теперь вы также должны определить after_command/1 иafter_error/1 функции обратного вызова:

defmodule BankAccountLifespan do
  @behaviour Commanded.Aggregates.AggregateLifespan

  def after_event(%BankAccountClosed{}), do: :stop
  def after_event(_event), do: :infinity

  def after_command(%CloseAccount{}), do: :stop
  def after_command(_command), do: :infinity

  def after_error(:invalid_initial_balance), do: :stop
  def after_error(_error), do: :stop
end

Обратный вызов after_command/1 позволит вам остановить агрегат, когда события не генерируются.

...