[Bug] ActiveSupport::Notifications : payload modifications not visible to single-arg subscribe blocks

Today I was writing a little wrapper around running shell commands, and wanted to wrap an ActiveSupport::Notifications.instrument call around Process.spawn. What I had looks something like this:

def spawn(params)
  env, command_line = prepare(params)
  ActiveSupport::Notifications.instrument('shell_command.spawn', env: env, command_line: command_line) do |payload|
    pid = Process.spawn(env, command_line)
    Process.wait pid
    payload[:exitstatus] = $?.exitstatus
    payload[:termsig] = $?.termsig

I checked and it seems that ActiveSupport::Notifications and the Instrumenter class are careful to pass the payload unmodified to the instrumented block, but the Event class calls payload.dup on initialization.

I can’t see any reason to forward the payload to the instrumented block if you aren’t allowed to modify it, so I would like to remove the .dup call and document the (currently undocumented) block parameter.

However, that line has been there for 11 years, and the payload block parameter is not documented, so maybe this is a really bad idea. In that case I’d love it if somebody could tell me how to get the behaviour I want, even if it’s more verbose/complicated for me to write.

Ah wait, this might actually be a bug. If I subscribe like ActiveSupport::Notifications.subscribe do |*args| instead of ActiveSupport::Notifications.subscribe do |event|, the Event object is not initialized until after the block runs, and my modified payload is visible.

… and it’s fixed in 6.1, seems like 6.0 is affected. Sorry for the noise, feel free to delete this topic :slight_smile: