Hi,
Thanks for follow-up!
On Thu, Aug 7, 2014 at 8:35 PM, James Roper <
ja...@typesafe.com> wrote:
> Biggest difficulty with this interface is the semantics - if it's already
> stopped before the callback is registered, what happens? If the answer is
> invoke onStop immediately, how do we ensure/help tasks to safely implement
> this to avoid race conditions, is synchronisation ok or may that cause
> deadlocks? Is it ok to invoke the callback synchronously?
Yeah - I'm comfortable sorting that kind of thing out, if we like the
larger approach. We could provide an abstract base class or other
helpers to ensure it's gotten right. (If not obvious, I didn't agonize
over interface details yet.)
I was going to limit this callback thing to sbt internals if not clear
- tasks and build code aren't supposed to use this directly.
> Run may also fail - eg port already taken.
Hmm indeed.
I think here the job could send an error event and then stop itself.
Or we could introduce the idea of an "exit code" kind of thing (it
could be an Option[Throwable] if we prefer). I'm worried things might
get more complex if we allow jobs to return results rather than simply
failing or not, though.
From the command line, it's sort of unclear what to do with the errors
(or logs, for that matter) from a job. What did you do for Play, just
go ahead and dump them to stderr even though somebody might be typing
?
For a UI it seems simpler, we can just display the error someplace.
Another question is how/when this ties back to State. I'm thinking the
stopping, or failure, of a job is allowed to affect the State in
between commands; while another command is running the job status
would just be queued somewhere to be seen by the next command but not
the current one. Or something like that. This would affect visibility
of job state to tasks; UIContext would be able to see the job status
sooner by observing events, but tasks would not see the list of jobs
or status of jobs change while the task is in flight. Not sure about
this, it's a problem to work through.
We should seriously consider an alternative to jobs where we instead
make tasks backgroundable - add the idea of executing a task outside
of the main sbt loop ... I haven't fully played out what that would
look like. Josh was talking about this at one point. I'm not sure
whether it's harder or easier than this jobs idea.
> Agreed. Don't break run.
> Also note here that it's not uncommon to provide
> your own run implementation, often delegating to the original run, to do
> some setup/tear down work, eg start/stop a database. This should also still
> work - though obviously this won't work with sbt-remote-control.
Hmm. That suggests we might need some sort of hooks for setup and
teardown - either around "any job with tag xyz" or specifically around
the run job.
Ideally people could easily port their "run" override to a
"backgroundRun" override or to overriding before/after run hooks or
something.
>> The solution could be de-generalized; i.e. instead of a general
>> BackgroundJob and tracking N jobs, we could just very specifically be
>> aware of a single RunJob. This would more or less be pulling what Play
>> has now down into generic sbt. I was just generalizing since it seemed
>> pretty easy and I can imagine wanting to background other things.
>
>
> Running multiple background jobs is required, people run multiple play sbt
> sub projects at once with independent sbt invocations, if sbt remote control
> means there's only one sbt, then multiple background jobs is required.
>
I guess I meant "one per project" or "one per run task" but yeah. I
think it's about as easy to make this general so I'm not seeing the
value in making it hardcoded to run. Though I am usually a fan of
hardcoding ;-)
> One thing not addressed here is how it will deal with invoking the same
> background run task twice... is it up to the client to check current
> background tasks to not do that, or will sbt provide some mechanism to
> ensure that doesn't happen?
Good point. I threw in the "tags" mechanism to give a way to check
current jobs, and I guess I was thinking the client would have to do
it (though the stock "backgroundRun" task would do it for you for
run).
Another question is about scopes: are jobs scoped to project/task?
Maybe that actually should be used rather than tags, so a job in the
"run" scope or a job in the "run in myproject" scope would be unique.
Or possibly tags should be scoped. Or maybe there's no job scope if
the job already has a pointer to its parent task, and the task is
scoped, then you don't need a separate scope on the job. That makes
sense to me actually, you'd do uniqueness by looking for a job from
the fully-scoped task and then you could if necessary also have tags
but maybe we don't need tags, just the scoped task the job came from.
Gah this is getting complicated ;-)
Oh I see you were about to say the same -
> And what the interface doesn't make clear is
> it's possible to list running tasks,
jobs! I called them jobs so we don't get confused ;-)
> but how does the client know which sub
> project/configuration/etc that task is? If you start your IDE and Play is
> already running, how does the IDE know which sub project to associate that
> running task with, so that, for example, if it attaches a debugger, it
> associates the debugger with the right classpath/sources?
If we associate each job with the fully-scoped task key that spawned
it, I think that would probably solve it ... ?
Havoc