Learning
VOL. XIII · NO. 27 · Elixir · 01 JAN 1970

IEx 与 REPL 实战

Elixir 编程 · 01 JAN 1970 · 5 min read · 927 words
· · ·

不要只把 REPL 当计算器:用 IEx 读代码、查进程、调试监督树和验证数据库查询。

本课目标
学完后,你能用 iex -S mix 进入项目,检查模块、调用函数、观察进程,安全地验证一个修改,而不是每次都先写脚本或重启服务。

一、启动方式

# 普通 Elixir REPL
iex

# 加载 Mix 项目、依赖和应用代码
iex -S mix

# 指定环境
MIX_ENV=test iex -S mix

# 启动项目但不自动启动应用
iex -S mix run --no-start

iex -S mix 会编译项目并加载依赖。是否启动应用取决于 Mix 和 Application 配置;连接真实数据库或外部服务前,先确认当前环境。

二、最常用的探索命令

h Enum.map/2          # 查看帮助
h Pipeline.Llm        # 查看模块文档
i value               # 查看值的类型和大小
v()                   # 查看上一条结果
v(2)                  # 查看历史第 2 条结果
c "tmp/demo.ex"       # 编译文件
r Pipeline.Dag        # 重新编译模块
exports Pipeline.Dag  # 列出导出函数
flush()               # 取出当前进程邮箱里的消息
  • h 用来读文档,i 用来确认数据形状。
  • v() 可以避免重复执行有副作用的调用。
  • r Module 适合开发环境;生产环境不要随意热编译模块。

三、用 IEx 检查真实数据

iex> text = "a\nb\n"
iex> String.split(text, "\n", trim: true)
["a", "b"]

iex> Pipeline.Dag.nodes()
[%{id: "news_pull", upstream: []}, ...]

iex> Pipeline.Repo.all(from e in Pipeline.PipelineExecution,
...>   order_by: [desc: e.id], limit: 3)
[%Pipeline.PipelineExecution{}, ...]

复杂表达式建议拆成多个绑定,先看中间结果,再继续管道。这样比把十步逻辑写成一行更容易定位数据在哪一步变形。

四、观察 BEAM 进程

Process.list() |> length()
Process.whereis(Pipeline.Repo)
Process.info(Process.whereis(Pipeline.Repo), [:status, :memory, :message_queue_len])

:observer.start()                 # 图形化观察器
:erlang.system_info(:schedulers_online)
Process.registered()

重点关注 :message_queue_len。邮箱持续增长通常意味着消费者处理太慢、消息格式不匹配,或者某个进程已经无法及时处理消息。

五、IEx 中的调试边界

# 纯函数可以直接验证
Pipeline.FeishuParser.parse("...")

# 查看异常,但不要吞掉根因
try do
  risky_call()
rescue
  error -> IO.inspect(error, label: "error")
end

# 追踪一个进程收到的消息
:sys.trace(pid, true)
:sys.trace(pid, false)

:sys.trace/2 只适合短时间、开发或受控诊断。生产环境优先使用 Logger、Telemetry 和监控,不要把所有消息长期打印出来。

六、用 IEx 验证配置与模块

Application.get_env(:pipeline, :start_oban)
Application.get_env(:pipeline, :llm)
Application.fetch_env!(:pipeline, :schema_prefix)

Code.ensure_loaded?(Pipeline.Jobs.NewsDigest)
function_exported?(Pipeline.Jobs.NewsDigest, :perform, 1)
Application.started_applications()

配置问题经常不是代码逻辑错误,而是环境变量、编译期配置和运行时配置混在一起。先在 IEx 里确认实际值,再决定改哪一个配置文件。

七、数据库查询的安全练习

import Ecto.Query

query = from e in Pipeline.PipelineExecution,
  where: e.status == ^"done",
  order_by: [desc: e.id],
  limit: 5

Pipeline.Repo.all(query)
Pipeline.Repo.to_sql(:all, query)

先用只读查询验证条件,再执行写操作。不要在生产 IEx 里直接复制未经检查的 delete_all 或裸 SQL。

八、把临时探索变成可复现代码

IEx 适合探索,不适合保存关键业务逻辑。验证出正确行为后,应把它变成:

  • 纯函数测试或 ExUnit 回归测试。
  • 可审查的 Mix Task。
  • 明确的 migration 或维护脚本。
  • 带日志、权限和幂等控制的后台 Job。

九、测验

1

加载 Mix 项目并进入 REPL 的命令是?

2

IEx 中查看模块或函数帮助使用?

3

i value 主要用于?

4

IEx 中查看上一条表达式结果使用?

5

Process.whereis(Pipeline.Repo) 返回什么?

6

进程的 message_queue_len 持续增长通常说明?

7

Pipeline.Repo.to_sql(:all, query) 的用途是?

8

生产环境长期追踪所有 GenServer 消息的做法?

9

IEx 探索出正确行为后,最好的下一步是?

10

MIX_ENV=test iex -S mix 的作用是?

**下一步:**用 IEx 验证一个真实查询,再把它写成 ExUnit 测试,形成可复现反馈回路。