在不产生事件的聚合中使用 Commanded 避免内存泄漏
Avoiding memory leaks with Commanded in an aggregate that doesn't produce an event
在 Elixir 1.7.4 上使用 Commanded 0.17.2 构建的应用程序经常 运行 内存不足。调查发现内存泄漏似乎是由不断增加的聚合实例引起的,这些实例从未停止。
相关聚合接收由外部系统触发的命令。在某些情况下,execute
函数 returns 一个事件,而在其他一些情况下,该命令应该被忽略,因此它 returns 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
)
我怀疑这是 Commanded 中的错误:
defp aggregate_lifespan_timeout(_context, []), do: :infinity
避免内存泄漏的一种方法是生成一个事件,即使没有人需要它。这将导致污染的持久事件存储而不是易失性内存,因此可能会在长期 运行.
中导致更大的问题。
我现在正在寻找一种方法来停止聚合实例,以防 execute
函数 returns 和 nil
。非常感谢任何解决方法的想法。
此问题已修复,将在 next release of Commanded 中提供。
拉取请求 #210 扩展聚合生命周期行为以包括 after_error/1
和 after_command/1
回调。
以前您只需定义一个 after_event/1
回调函数来实现 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
回调将允许您在没有生成任何事件时停止聚合。
在 Elixir 1.7.4 上使用 Commanded 0.17.2 构建的应用程序经常 运行 内存不足。调查发现内存泄漏似乎是由不断增加的聚合实例引起的,这些实例从未停止。
相关聚合接收由外部系统触发的命令。在某些情况下,execute
函数 returns 一个事件,而在其他一些情况下,该命令应该被忽略,因此它 returns 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
)
我怀疑这是 Commanded 中的错误:
defp aggregate_lifespan_timeout(_context, []), do: :infinity
避免内存泄漏的一种方法是生成一个事件,即使没有人需要它。这将导致污染的持久事件存储而不是易失性内存,因此可能会在长期 运行.
中导致更大的问题。我现在正在寻找一种方法来停止聚合实例,以防 execute
函数 returns 和 nil
。非常感谢任何解决方法的想法。
此问题已修复,将在 next release of Commanded 中提供。
拉取请求 #210 扩展聚合生命周期行为以包括 after_error/1
和 after_command/1
回调。
以前您只需定义一个 after_event/1
回调函数来实现 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
回调将允许您在没有生成任何事件时停止聚合。