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 '20 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 '20 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 '20 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 '20 at 11:26
  • Here's a gist of the code. Nov 16 '20 at 11:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.