mount

tolitius 2017-04-07T01:32:32.431413Z

@oahner ^:on-reload :noop should only care about namespace recompilations / state redefinition. start / stop should work as usual.

tolitius 2017-04-07T01:32:42.432375Z

can you give an example?

oahner 2017-04-07T01:33:06.434856Z

let's see

oahner 2017-04-07T01:46:23.512705Z

it's the update-meta! in mount-it; it always runs even with :noop so the state gets overwritten with the blank state in @meta-state

oahner 2017-04-07T01:47:34.519428Z

I had assumed it would behave like a defonce but no; the derefable state is defined with defonce but the content always gets reset by the defstate call

oahner 2017-04-07T01:54:33.560488Z

What I wanted out of :noop is a defonce-like defstate that does absolutely nothing on a subsequent call and keeps the initial state running as-is

oahner 2017-04-07T01:56:58.575638Z

While it does keep the initial state running through a reload (a webserver that binds to port 80 in the :start fn will not stop), it still replaces the state's @meta-state entry with a new, not running state, so the next (stop) does nothing and the subsequent (start) fails to start the actual webserver since port 80 is still in use by the previous state

tolitius 2017-04-07T01:58:39.588308Z

yep, I see it. it does not cleanup the second time, since it "thinks" the state is stopped:

boot.user=> (require '[mount.tools.graph :as g])
nil
boot.user=> (pprint (g/states-with-deps))
({:name "#'boot.user/beatles",
  :order 1,
  :status #{:stopped},
  :deps #{}})

oahner 2017-04-07T01:58:54.589756Z

exactly 🙂

tolitius 2017-04-07T01:59:14.591737Z

wonder why I have not noticed it before..

tolitius 2017-04-07T01:59:32.593703Z

since I frequently have http server as a reload noop

tolitius 2017-04-07T02:00:00.597044Z

I guess the kicker is in the second call to start

tolitius 2017-04-07T02:00:23.599932Z

which usually does not happen, since it's a noop to begin with: i.e. the same state keeps running

oahner 2017-04-07T02:00:54.603287Z

well, the second start sees a stopped state since mount-it replaces the entry with a blank one

tolitius 2017-04-07T02:01:03.604262Z

this is an interesting corner case: you redefined a noop state with a noop

oahner 2017-04-07T02:01:08.604803Z

the only trace of it is in @mount/running

tolitius 2017-04-07T02:01:30.607078Z

right you can:

boot.user=> (mount/running-states)
#{"#'boot.user/beatles"}

tolitius 2017-04-07T02:01:39.607897Z

not to get down to atoms

oahner 2017-04-07T02:01:52.609086Z

I've been poking around 😉

tolitius 2017-04-07T02:02:10.610844Z

that's very good 🙂

tolitius 2017-04-07T02:02:18.611701Z

so let's replay this scenario from the way you work with the real namespace

tolitius 2017-04-07T02:02:39.613623Z

you have something like:

(defstate ^{:on-reload :noop} http-server 
                              :start (start-www (config :hubble))
                              :stop ((:stop-server http-server)))

tolitius 2017-04-07T02:02:44.614032Z

defined

tolitius 2017-04-07T02:02:53.614850Z

then you recompile the ns

tolitius 2017-04-07T02:03:00.615568Z

http-server keeps running

oahner 2017-04-07T02:03:52.620674Z

correct, but after the recompile, @meta-state's #'http-server entry now points to a new var

tolitius 2017-04-07T02:04:02.621728Z

let me reproduce it with: https://github.com/tolitius/stater/tree/master/smsio

tolitius 2017-04-07T02:04:13.622784Z

one sec

oahner 2017-04-07T02:09:23.652130Z

as an aside, if :on-reload :noop really was a noop on subsequent calls, there is a possibility that the initial running service (in this case http-server) could break with clojure.tools.namespace's refresh, since it undefs pretty much everything, even a defonce, but I'm not sure it actually deletes anything from memory, so the thread spawned by start-www probably wouldn't get affected

tolitius 2017-04-07T02:09:45.654251Z

java.net.BindException: Address already in use
java.lang.RuntimeException: could not start [#'app.www/web-server] due to
hmm.. I wonder what "broke?" it. looks like a noop state should not be marked as :stopped

oahner 2017-04-07T02:10:05.656128Z

that's the behavior I get alright

oahner 2017-04-07T02:10:24.658010Z

also weird that it just said "due to" and stops there

oahner 2017-04-07T02:10:34.659170Z

I get that too

tolitius 2017-04-07T02:10:37.659428Z

mount would still remember states in t.n.refresh

tolitius 2017-04-07T02:10:48.660617Z

you can do *e

oahner 2017-04-07T02:10:51.660886Z

yep, it sure does, thx to disable-reload!

tolitius 2017-04-07T02:10:53.660995Z

to see the exception

oahner 2017-04-07T02:13:21.675161Z

I suppose t.n.refresh can't entirely unmap the existing web-service since a) mount still has a reference to it and b) the whole environment gets captured by the closure that calls start-www, but I'm pulling facts out of thin air on this subject

oahner 2017-04-07T02:15:42.688830Z

I sure am glad I'm not the only one getting this behavior tho, I spent the entire day looking at examples and other projects to see where I was using mount wrong

tolitius 2017-04-07T02:16:49.695145Z

ok, so https://github.com/tolitius/mount/blob/master/src/mount/core.cljc#L150 should not be called (when (and ((running-states) s-name) (= :noop on-reload)))

tolitius 2017-04-07T02:17:25.698458Z

I am sure something has introduced this.. I wonder what it was

tolitius 2017-04-07T02:17:36.699500Z

:reload stuff is really hard to test in cljs

tolitius 2017-04-07T02:18:07.702334Z

it might be the cljs direction that pushed a bad commit to clj side

oahner 2017-04-07T02:18:57.706809Z

that sounds like a good explanation

oahner 2017-04-07T02:20:06.713095Z

it must be rather recent too, this is a pretty standard setup

tolitius 2017-04-07T02:25:02.739993Z

yea..

tolitius 2017-04-07T02:25:40.743679Z

so now I wonder whether a :noop state could/should be ever redefined..

tolitius 2017-04-07T02:25:48.744348Z

i.e. one thing is to recompile a namespace

tolitius 2017-04-07T02:26:01.745399Z

another thing is to manually redefine a state

oahner 2017-04-07T02:27:08.751011Z

well, a t.n.refresh doesn't break a running web server, even tho everything under it gets undef'd

oahner 2017-04-07T02:28:13.756414Z

the lesser recompiles, either (require ... :reload) and just copy/pasting the defstate block into the repl, don't actually undef vars defined with defonce either, so they're pretty safe

oahner 2017-04-07T02:29:38.764089Z

meanwhile, when running a webserver in debug mode, most projects I've seen refer to the handler by ref so it always points to the latest defined routes anyway

oahner 2017-04-07T02:30:29.769313Z

I think a :noop should only be lifecycled through an explicit start/`stop` call

tolitius 2017-04-07T02:31:07.773301Z

right, that is how it was designed to work 🙂

tolitius 2017-04-07T02:31:21.774651Z

but.. how do you redefined that state if you need to?

oahner 2017-04-07T02:32:56.783452Z

I suppose swap-states could be made to be the recommended way to do such a thing

oahner 2017-04-07T02:33:12.784820Z

OR

oahner 2017-04-07T02:33:38.787286Z

make it so a :noop state can only be redefined if it's not running

oahner 2017-04-07T02:33:45.787923Z

but that's less explicit

oahner 2017-04-07T02:35:46.798853Z

what I've been doing so far is comment out the on-reload meta on the defstate, running it, then uncommenting it with the modified defstate again

oahner 2017-04-07T02:36:02.800260Z

but that's clearly inferior to the alternatives

tolitius 2017-04-07T02:37:17.806502Z

I am looking at it.. the fix is not hard. the tricky part is to make "macro + var + ns" work in both clj and cljs

tolitius 2017-04-07T02:37:46.809207Z

since cljs does not really have vars and ns 🙂

oahner 2017-04-07T02:38:23.812434Z

yeah, that's why I still use a good old ctrl-r for cljs ^^

oahner 2017-04-07T02:38:48.814612Z

figwheel makes development painless enough

tolitius 2017-04-07T02:39:35.818859Z

I guess I have not noticed it lately since iff I change the ns where I have things like server(s) defined, I want the server to restart..

oahner 2017-04-07T02:40:18.822500Z

that's probably it, I haven't seen :noop used much outside of the luminus template

tolitius 2017-04-07T02:41:14.827878Z

yea, I love these challenges.. only when you think "ok, this is finally rock solid" people who pay attention have a question 🙂

oahner 2017-04-07T02:41:42.830308Z

heck, for now I think I'll just put the web-server into its own namespace without making it :noop and disable-reload! it

oahner 2017-04-07T02:42:02.831861Z

that should do the trick

tolitius 2017-04-07T02:42:58.836955Z

why do you have it :noop to being with: what do you change in that namespace that does not require a server restart?

oahner 2017-04-07T02:43:26.839539Z

ah, see this is where my scenario is unique

oahner 2017-04-07T02:43:32.840128Z

I have everything in core.clj ^^'

oahner 2017-04-07T02:43:54.842233Z

it's a brand new project, haven't started splitting it off into multiple files yet

oahner 2017-04-07T02:44:05.843196Z

nobody in their right mind would do that ,right?

tolitius 2017-04-07T02:44:06.843284Z

ah.. ok

oahner 2017-04-07T02:44:41.846477Z

s/cljs/clj

oahner 2017-04-07T02:46:29.856268Z

this is a fun bug tho

oahner 2017-04-07T02:47:15.859940Z

I learned more about how clojure deals with namespaces in the last 24 hours than in the 2 years before

tolitius 2017-04-07T02:51:13.881212Z

I guarantee you there is even more to learn in that direction 🙂

oahner 2017-04-07T02:51:49.884333Z

yeeeah, quite the rabbit hole

tolitius 2017-04-07T02:52:40.888588Z

i.e. the next 2% https://gist.github.com/tolitius/c17b2d4a98eabb591926

tolitius 2017-04-07T02:53:11.891294Z

those times when I thought I'll just use a bootstrapped cljs to deal with ns api..

tolitius 2017-04-07T02:53:46.894474Z

it was a couple of years ago, I was too naive back then

oahner 2017-04-07T03:31:31.081579Z

oh wait, I was wrong

oahner 2017-04-07T03:32:11.084567Z

t.n.refresh does break the initial state with :noop

oahner 2017-04-07T03:32:29.086087Z

well, I mean, it still works, it'll just never pick up any further changes

tolitius 2017-04-07T03:34:01.092930Z

can you try a new 0.1.12-SNAPSHOT?

tolitius 2017-04-07T03:34:15.093985Z

with your previous (i.e. initial) setup

oahner 2017-04-07T03:34:23.094577Z

sure thing

oahner 2017-04-07T03:39:17.117232Z

taking a while, had to nuke my .m2 repo

tolitius 2017-04-07T03:41:30.127528Z

strange.. I can pull it, and see it here: https://clojars.org/mount/versions/0.1.12-SNAPSHOT

oahner 2017-04-07T03:42:06.130276Z

weird, my local copy wouldn't update itself

tolitius 2017-04-07T03:43:14.135498Z

even after you delete it?

oahner 2017-04-07T03:43:22.136189Z

oh yes that always works

oahner 2017-04-07T03:43:28.136662Z

it's fine now

oahner 2017-04-07T03:43:50.138217Z

that actually happens to me quite often with SNAPSHOT releases

oahner 2017-04-07T03:44:02.139262Z

I like the alphaN convention for that

oahner 2017-04-07T03:45:12.144731Z

beautiful!

oahner 2017-04-07T03:45:14.144905Z

works flawlessly

oahner 2017-04-07T03:45:24.145723Z

many, many thanks!

oahner 2017-04-07T03:45:52.148081Z

well, for clj at least

tolitius 2017-04-07T03:47:02.153581Z

yea, I am testing for cljs.. it is a bit more involved 🙂

oahner 2017-04-07T03:48:24.159526Z

so now ring's wrap-reload works without restarting the state, and t.n.refresh :after 'reset works by restarting the state

oahner 2017-04-07T03:48:32.160224Z

just perfect

oahner 2017-04-07T03:48:59.162244Z

I can't think of a nicer REPL environment, got all the bases covered

tolitius 2017-04-07T03:53:01.181374Z

great 🙂 do you need to refresh it often?

tolitius 2017-04-07T03:53:15.182427Z

I usually have something like: https://github.com/tolitius/stater/blob/master/smsio/dev/dev.clj

tolitius 2017-04-07T03:53:45.184795Z

where I might add a mount/stop-except to (stop)

tolitius 2017-04-07T03:54:04.186195Z

and mostly use (reset)

oahner 2017-04-07T03:54:08.186457Z

not unless I break something in my REPL really

tolitius 2017-04-07T03:54:18.187216Z

right, ok

oahner 2017-04-07T03:54:29.188082Z

for the most part ring-reload does everything

oahner 2017-04-07T03:55:11.191271Z

but having t.n.refresh is helpful for those edge cases where the state has just diverged too badly

oahner 2017-04-07T03:56:26.197065Z

ohh, didn't know about mount-up

oahner 2017-04-07T03:56:27.197186Z

interesting

tolitius 2017-04-07T03:57:35.202225Z

yea, I used to carry this everywhere: https://github.com/tolitius/mount/blob/master/dev/clj/app/utils/logging.clj

oahner 2017-04-07T03:57:56.203751Z

ohh, I love cprop btw, I had a small utils module in my projects that pretty much did exactly that but worse and with less features, was an easy swap

tolitius 2017-04-07T03:57:58.203932Z

but then I had spare 30 min "to decouple"..

tolitius 2017-04-07T03:58:12.204929Z

ah, thanks 🙂

tolitius 2017-04-07T03:58:49.207768Z

yea, cprop also started as a traveler file from project to project, until "I got my self together"..

oahner 2017-04-07T03:59:00.208591Z

hehe

tolitius 2017-04-07T03:59:36.211255Z

I mostly use it with envoy the last couple of years: https://github.com/tolitius/envoy

tolitius 2017-04-07T04:00:06.213942Z

i.e. merging overrides from consul

tolitius 2017-04-07T04:01:04.219492Z

i.e. https://github.com/tolitius/envoy#merging-configurations

oahner 2017-04-07T04:01:24.221318Z

holy crap

tolitius 2017-04-07T04:01:28.221689Z

when I land to places with no consul, I start my own 🙂

oahner 2017-04-07T04:01:45.223011Z

that's neat!

tolitius 2017-04-07T04:01:48.223202Z

and then slowly convince people that it is a good idea

tolitius 2017-04-07T04:02:31.226755Z

then I add a sprinkle of vault https://www.dotkam.com/2017/01/10/hubble-space-mission-securely-configured/ and I am a happy camper

oahner 2017-04-07T04:02:41.227435Z

a centralized server for all your projects' configuration and credentials that auto updates to your clojure config at runtime? what's not to like 🙂

tolitius 2017-04-07T04:04:13.234333Z

right.. "auto updates to your clojure config at runtime" may not be to everyone's liking (ops people don't find this too appealing), but merging overrides (and secrets from vault) on start instead of carrying different files / ENV for different environments is a big win

oahner 2017-04-07T04:04:32.235972Z

exactly

tolitius 2017-04-07T04:12:03.268835Z

tested ":noop" in cljs. visually works

tolitius 2017-04-07T04:12:13.269559Z

can also redefine it after it is stopped

tolitius 2017-04-07T04:15:19.283698Z

cljs.user=> (defstate ^{:on-reload :noop} web-server :start 28 :stop :stopped)
#'cljs.user/web-server

cljs.user=> (mount/start)
{:started ["#'cljs.user/web-server"]}

cljs.user=> @@#'cljs.user/web-server
28

cljs.user=> (defstate ^{:on-reload :noop} web-server :start 28 :stop :stopped)
#'cljs.user/web-server

cljs.user=> @@#'cljs.user/web-server
28

cljs.user=> (mount/stop)
{:stopped ["#'cljs.user/web-server"]}

cljs.user=> (defstate ^{:on-reload :noop} web-server :start 42 :stop :stopped)
#'cljs.user/web-server

cljs.user=> (mount/start)
{:started ["#'cljs.user/web-server"]}

cljs.user=> @@#'cljs.user/web-server
42

oahner 2017-04-07T04:16:15.287942Z

nice!

oahner 2017-04-07T04:16:41.290006Z

oh, so a noop state gets redefined if it's stopped?

tolitius 2017-04-07T04:16:47.290461Z

yes

oahner 2017-04-07T04:16:51.290764Z

perfect

tolitius 2017-04-07T04:16:53.290924Z

I thought it should be

oahner 2017-04-07T04:16:59.291363Z

makes sense to me

oahner 2017-04-07T04:18:32.298220Z

so I clicked and clicked and clicked from those last links you shared and now I'm looking at hazelcast

oahner 2017-04-07T04:18:58.300104Z

how I never heard of it before is beyond me, but damn, that looks nice

tolitius 2017-04-07T04:19:14.301231Z

yea, I love it

oahner 2017-04-07T04:19:23.301926Z

am I reading correctly that this is on par with redis?

tolitius 2017-04-07T04:19:32.302592Z

especially if you are coming from JVM, it is really great

oahner 2017-04-07T04:19:40.303181Z

well, yeah, pretty much

oahner 2017-04-07T04:20:04.304922Z

I've been fighting with my IT guys to get redis and so far it's been blocked because "not supported on Windows Server" well enough and we're a microsoft shop

oahner 2017-04-07T04:20:12.305462Z

but this looks like it might fit the bill

tolitius 2017-04-07T04:20:58.308973Z

hazelcast is quite robust. redis is definitely a lot more known

tolitius 2017-04-07T04:21:12.310036Z

but "hz" guys are really active

tolitius 2017-04-07T04:21:34.311640Z

and it has lots of solid features

oahner 2017-04-07T04:21:45.312465Z

well that and I skimmed through the readme on https://github.com/tolitius/chazel

oahner 2017-04-07T04:21:48.312637Z

damn

tolitius 2017-04-07T04:22:49.317106Z

chazel only implements features I actively use. it is minor compare to what hazelcast can do

oahner 2017-04-07T04:23:30.320034Z

only

oahner 2017-04-07T04:23:31.320152Z

lol

tolitius 2017-04-07T04:23:43.320947Z

I am thinking on adding "Continuous Query Cache"

tolitius 2017-04-07T04:24:15.323207Z

they had it in the paid version, but now it is open sourced

oahner 2017-04-07T04:24:23.323910Z

well, either way, there goes my weekend

tolitius 2017-04-07T04:24:33.324677Z

haha, yea, good luck 🙂

tolitius 2017-04-07T04:25:10.327213Z

I am sure you'll get a kick out of hazelcast, it is really simple, straight forward and quite powerful

tolitius 2017-04-07T04:25:27.328518Z

problems start when you have large heaps

tolitius 2017-04-07T04:25:34.329036Z

i.e. over 70, 80 gigs

tolitius 2017-04-07T04:25:50.330130Z

they have an "off heap" storage as well, but it is paid

tolitius 2017-04-07T04:26:23.332537Z

but usage with a reasonable heap is quite solid

oahner 2017-04-07T04:26:44.334078Z

heh, if we ever have a system at work that requires so much heap, it'll be a nice problem to have

oahner 2017-04-07T04:27:11.335902Z

the problems I deal with aren't exactly web scale or big data

tolitius 2017-04-07T04:27:42.338240Z

once you have memory to put things in, you put more every day 🙂

oahner 2017-04-07T04:27:50.338837Z

true ^^