Arc Forumnew | comments | leaders | submitlogin
Automatic .arc reloading in background
28 points by byronsalty 6122 days ago | 9 comments
Here's a little snippet that will start a background thread that checks mtimes of a specified list of files, if any one changes then it will be reloaded in the background. I find this very useful to put right before I call (asv) so that as I develop I can just leave the server running.

  (def reload-check (paths (o mtimes (table)))
    (sleep 5)
    (map [if (no (mtimes _))
             (= (mtimes _) (mtime _))
             (no (is (mtimes _) (mtime _)))
             (do
               (= (mtimes _) (mtime _))
               (load _))]
          paths)
    (reload-check paths mtimes))
And then:

  (def csv ()
    (prn "starting chat server")
    (thread (reload-check '("chat.arc")))
    (asv))


8 points by CatDancer 6122 days ago | link

Nice! If you don't want to wait five seconds after saving your file, you could stick a call to your reload-check (without the sleep or the loop) in srv.arc at the point a request comes in:

    (def handle-request (s (o life threadlife*))
      (if (len< (pull dead srvthreads*) threadlimit*)
          (let (i o ip) (socket-accept s)
  +         (atomic (reload-check ...))
            (++ requests*)
though of course you wouldn't want to do this on a server that had a lot of requests coming in, since it would do the check on every request.

-----

2 points by byronsalty 6122 days ago | link

Yep this is definitely for dev only.

I found in practice that 5 seconds we fast enough, I would save the file, switch to browser and refresh and it would be there. Of course 5 seconds is the worst case - 2.5 seconds would be the average.

-----

5 points by sjs 6121 days ago | link

This is great, thank you. If I have to wait any time I get antsy so I changed the interval to 3s. I also changed map to each and got rid of the "* redefining foo" noise.

  (def reload-check (paths (o mtimes (table)))
    (sleep 3)
    (each p paths
      (if (no (mtimes p))
           (= (mtimes p) (mtime p))
	  (isnt (mtimes p) (mtime p))
           (do
	     (= (mtimes p) (mtime p))
             (tostring (load p)))))
    (reload-check paths mtimes))

-----

5 points by mattjones 6121 days ago | link

This is actually a really useful feature. The Ramaze Ruby framework does this by default and I like it a lot.

One thing that makes it even more convenient is automatically detecting what files to reload. Ramaze does it by using Ruby's $LOADED_FEATURES and $LOAD_PATH variables. You can get the same conveniece with Arc with a simple modification to arc.arc:

    (= loaded-files* nil)  ; added
    
    (def load (file)
      (w/infile f file
        (whilet e (read f)
          (eval e)))
      (= loaded-files* (adjoin file loaded-files*)))  ; added
Now you can just use loaded-files* in your reload-check function.

-----

3 points by byronsalty 6118 days ago | link

Nice. I was trying to think of an easy way to do this.

In order to not have to muck with the internals of load itself I wonder if you could wrap the saving path name functionality but then call the original load. Maybe this would be some new synatx / ability to add to the language? Of course this is just aspects which I thought Lisp could do so - I'm probably missing something.

-----

1 point by cooldude127 6118 days ago | link

that is very cool.

-----

2 points by cooldude127 5988 days ago | link

this would suck without tail call optimization. lol

-----

1 point by lojic 6115 days ago | link

How about parameterizing csv with the sleep value ?

-----

1 point by pibefision 5709 days ago | link

Can someone explain where we should put this code to have this funcionality in every project?

-----