I have a job_start() call like this:

let options = {
      \ 'stdoutbuffer': [],
      \ 'handler': a:handler,
      \ }
let command = s:build_command(a:cmd)
let s:job = job_start(command, {
      \ 'out_cb':   function('s:on_stdout_vim', options),
      \ 'close_cb': function('s:on_close_vim', options),
      \ 'exit_cb':  function('s:on_exit_vim', options)
      \ })

The external command being run is ps -axco command.

Normally when the job runs, the out_cb is invoked multiple times, then the close_cb once, and finally the exit_cb once.

However when my code is invoked twice in rapid succession the first job's close_cb is never invoked. I haven't been able to figure out why.

This is a problem because the job result is handled in my close_cb handler (I only added an exit_cb to try to debug this problem). So if the close_cb handler isn't invoked the result of the job is lost.

The docs says that exit_cb is called when the job ends and close_cb is called when the channel is closed. So exit_cb sounds more appropriate because I care about the job, not the underlying channel.

However the exit_cb docs also say that:

data can be buffered, callbacks may still be called after the process ends.

I think that's saying that out_cb can be called after exit_cb. If so, it would suggest that I can't rely on exit_cb to know when I have everything produced by the job on stdout.

Furthermore the close_cb docs say that:

Vim will invoke callbacks that handle data before invoking close_cb

Which sounds like I can rely on having all the data when close_cb is invoked. And this is why I'm using close_cb instead of exit_cb to act on the job's result. Except close_cb doesn't get invoked when this other plugin's job is around.

Am I right to use close_cb not exit_cb? If so, why would it not be invoked? When would it be right to use exit_cb?

  • 1
    Can you post a minimal working example which exhibits the reported behavior? Does it help if you handle the job result in the exit_cb handler, and write sleep 1m at the top (to give some time to pending callbacks)?
    – user938271
    Nov 13, 2020 at 12:44
  • I can reproduce this consistently with the two plugins, but haven't been able to come up with a minimal example. Handling the result in exit_cb would work here, though the 1ms sleep is a bit arbitrary, but I'd like to understand why close_cb doesn't get called. Nov 13, 2020 at 14:59
  • 1
    I had some idea as to what is causing the issue, but without a minimal example, I can't be sure. Anyway, see this answer. sleep 1m is not that arbitrary; it's the least amount of time Vim can sleep, and in my experience, it's enough for all pending callbacks to have been processed.
    – user938271
    Nov 13, 2020 at 15:37
  • I store a reference to each job in a dictionary; keys are incrementing ids and values are jobs. sleep 1m (or even 10m doesn't help). I'll keep trying to produce a minimal example. Nov 16, 2020 at 11:26
  • Here's a gist of the code. Nov 16, 2020 at 11:32


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.