我在做Elixir应用程序时学到的东西
最近,我正在为我们的一个客户使用Elixir编写一个后台工作者。这篇文章是关于我在编写工作程序时学到的东西。
添加十进制数字
我试着为小数类型做加法,就像我们做整数的方法一样:


它引发了一个算术错误,因为十进制有一个基础结构:%Decimal{coef: coefficient(), exp: exponent(), sign: sign()}。
我检查了十进制库,发现它有一个加法函数,可以将十进制或整数值相加。因此,加法可以按以下方式进行。

比较十进制值
整数的比较可以用== 算子来完成。

那么小数呢?

由于== 操作符的RHS(右侧)上的值不是小数,所以它返回错误。
我尝试使用Decimal.new,如下所示:

根据警告信息,我尝试使用Decimal.from_float和Decimal.cast,如下所示:

但这也会返回错误。
然后我试着向Decimal.new传递一个字符串,如下所示:

并且成功了。
使用find_in_batches的方法
在处理一个业务用例时,获取待处理订单并处理它们,代码如下:
defp orders_query() do
from(order in Order,
where: order.status == ^@pending
)
end
def perform do
orders_query()
|> Repo.all()
|> Enum.each(fn order ->
update_order(order)
end)
end
上述代码将在内存中一次性加载所有的记录。我决定在Elixir中搜索类似于Rails中find_in_batches的东西,我发现了这个讨论。
更新后的代码如下:
def perform do
Repo.transaction(fn ->
orders_query()
|> Repo.stream()
|> Enum.each(fn order ->
update_order(order)
end)
end)
end
我使用了Repo.stream,它默认以500条为一个批次获取记录,并且需要用一个事务来包装。
递归
在上面的方法中,我面临一个问题。当更新记录的时间超过超时时,Ecto会产生一个超时错误,我在这里描述过。
我通过使用递归来解决了这个问题,具体如下:
@batch_size 500
def perform do
remaining_records_count()
|> iterate_multiple_times()
end
defp remaining_records_count do
orders_query()
|> Repo.aggregate(:count)
end
defp iterate_multiple_times(count) when count <= @batch_size,
do: make_account_balance_available()
defp iterate_multiple_times(_count) do
make_account_balance_available()
remaining_records_count()
|> iterate_multiple_times()
end
在上面的代码中,iterate_multiple_times/1 是一个递归函数,它调用自己直到没有任何剩余的记录。
我希望你在使用Elixir构建任何应用程序/库时,会发现这些学习内容对你有帮助。