cespare / reflex

Run a command when files change
MIT License
3.39k stars 136 forks source link

--sequential runs --start-service invocations sequentially #25

Closed alecthomas closed 9 years ago

alecthomas commented 9 years ago

Hi,

I understand that strictly speaking, this makes sense, but practically I think it is not that useful. I have something like the following in a config file:

-r '.*\.go' -- go build -v -i ./cmd/foo ./cmd/bar
-s -r '.*\.go' -- go run ./cmd/foo/main.go
-s -r '.*\.go' -- go run ./cmd/bar/main.go

The goal is to rebuild all dependencies of foo and bar, then start them as services. Under normal (parallel) operation there is no way to guarantee that the build is to be completed before restarting the services. This often results in the services restarting before the dependencies have been rebuilt.

I tried to use --sequential, but in that case the first line completes, then the second line runs and prevents the third from running. I actually expected both --start-service lines to execute because I interpreted "service" as a background service. IMO, practically, this makes sense. What do you think?

Alec

cespare commented 9 years ago

I don't generally use --sequential so I hadn't really considered its interaction with --start-service. I agree that it it's not that useful in its current form. It's not clear to me that ignoring --sequential for services would be intuitive, though.

In any case, I think a better approach in this example is to use two reflex commands, not three. Something like:

-s -r '.*\.go' -- sh -c 'go build -v -i -o foo ./cmd/foo && ./foo'
-s -r '.*\.go' -- sh -c 'go build -v -i -o bar ./cmd/bar && ./bar'

Does that work for you?

alecthomas commented 9 years ago

I considered that approach, but avoided it because foo and bar effectively depend on largely the same code, which would result in redundant builds and load. Additionally, there are other steps that are more expensive (eg. protobuf code generation) that it would be good to avoid duplicating.

So yes it works, but is not ideal.

Edit: also it seemed there could be a race where between one service building and starting, the other could erase the generated files. I'm not sure if the Go toolset guarantees atomic replacement of its packages, but other tools likely do not.

cespare commented 9 years ago

In my experience, the go tool generally avoids redundant work. The shared libraries should only be rebuilt on change. The protobuf stuff is more problematic, though.

New idea:

-r '\.go$' -- bash -c 'go build ... && protoc ... && other-expensive-compile-tasks'
-s -g cmd/foo/cmd -- ./cmd/foo/cmd
-s -g cmd/bar/cmd -- ./cmd/bar/cmd

i.e. for the server tasks, detect that the server binary changed and rerun it.

alecthomas commented 9 years ago

Ah nice, that should work. Thanks.