unison icon indicating copy to clipboard operation
unison copied to clipboard

[Discussion] IO Watch Expressions

Open ChrisPenner opened this issue 10 months ago • 7 comments

This is an old Branch I'm just making a PR for to open the discussion about it since it comes up in Discord quite often.

It proves the concept of io> watch expressions isn't too hard to build, it's more a matter of design at this point. Some questions:

  • Do we re-run on every save or just when a unison dependency changed?
  • Do we block UCM till it's done so we can show the result, or do we just dump the output into UCM's stdout whenever it's done even if you were typing a command?
  • If it takes a long time to run (or is a server that doesn't complete) do we kill the old one when you save or do we always wait for a full run to complete?

Certain use-cases require different permutations of these, maybe we can come up with 2 or 3 different types of watch expressions that handle each purpose, but finding good names and explaining how they work isn't trivial.

ChrisPenner avatar Apr 02 '24 19:04 ChrisPenner

Here's my use case and my thoughts, basically I'm just looking for a live-reload of local.interactive:

  • Write some HTML using the html lib, which gets served by a local.interactive server
  • When changing some HTML, no need to manually run the server again, gaining a tiny bit of dev speed.

Similiar to ~reStart or vite dev this helps with making an app that serves HTML.

Do we re-run on every save or just when a unison dependency changed? On save, I'd say.

Do we block UCM till it's done so we can show the result, or do we just dump the output into UCM's stdout whenever it's done even if you were typing a command?

No real preference here.

If it takes a long time to run (or is a server that doesn't complete) do we kill the old one when you save or do we always wait for a full run to complete?

I believe most dev servers kill the old one, not sure about this tho.

zetashift avatar Apr 02 '24 20:04 zetashift

My thoughts:

Do we re-run on every save or just when a unison dependency changed?

On every save. If someone has io> Instant.now in their scratch file they are going to expect the output to update even though their code doesn't.

But one concern that I would have is if people have editors that auto-save every second or something. This could get really annoying for them. But I think that it would be reasonable to release it as a new feature and see whether people complain about this (maybe they just will use run instead of IO watch expressions?)

Do we block UCM till it's done so we can show the result, or do we just dump the output into UCM's stdout whenever it's done even if you were typing a command?

No strong preference is obvious to me right now, as long as I can ctrl-c it if we opt for the former.

If it takes a long time to run (or is a server that doesn't complete) do we kill the old one when you save or do we always wait for a full run to complete?

The use-case that I have in mind is live reloading of an HTTP server, and in that case I think that we want to kill it.

ceedubs avatar Apr 02 '24 20:04 ceedubs

@ceedubs

No strong preference is obvious to me right now, as long as I can ctrl-c it if we opt for the former.

Does this imply that UCM is blocking for it to finish? Does a ctrl-c in UCM go to UCM itself (if you run a long-running history command) or to the IO watch; and if you have many IO watches, which one?

ChrisPenner avatar Apr 02 '24 21:04 ChrisPenner

@ChrisPenner hmm good questions. I wasn't considering the case of multiple io> watch expressions.

One option is that ucm runs all IO watch expressions and blocks on the result, with ctrl-c interrupting all of them. But I feel like this could get annoying in the case of an HTTP server where you might not want to ctrl-c every time as you view/edit/etc as you work on changes.

But if it just runs all of them in the background then it will be easy to forget that they might be running. And there isn't an obvious way to stop them.

I'd imagine that the case of multiple running would be fairly rare unless we change '{IO, Exception} [test.Result] terms to have an io> when the are edited.

So maybe we go with the blocking approach and try it on for size? If we are hesitant to commit to this feature we could put it behind some sort of flag.

ceedubs avatar Apr 03 '24 12:04 ceedubs

I'd imagine that the case of multiple running would be fairly rare

I'd agree with this, but I can imagine that Unison might be the exception here, because people would like to run multiple services at once to do some sortof test? Just because of how easy it is to do microservices.

So maybe we go with the blocking approach and try it on for size?

For sure this though! :+1: even in Vite, Elixir-land or Scala live-reload isn't ideal, but they are comfy to use for almost everything.

zetashift avatar Apr 08 '24 23:04 zetashift

Just wanted to +1 this since it came up in discord (when discussing dev live-reloading for web apps)

edit: I would probably use this to do io> deployDev where dev is an actual non-local environment, so it shouldn't block UCM. Related: is there a best practice on doing deploys to unison cloud? Is it expensive to do ultra frequent deploys?

tapegram avatar May 12 '24 17:05 tapegram

Here's another perspective by @dfreeman

Yep! IO watch expressions would be a nice ergonomic replacement for some of the simpler hotswap use cases and would make the more complex ones work more smoothly, since you could do io> do TokenMapping.send myTokens and not need to worry about it not rerunning in the case of a cached result (plus you could avoid the coerceAbilities hack)

zetashift avatar May 16 '24 21:05 zetashift