The closest thing you can get in irb, is to use Rails' `reload!` after making changes to your files. I don't remember if irb supports this kind of stuff out of the box, perhaps good old `require` works.
Differences:
- Clojure has namespaces, so you can reload just one unit rather than the whole code - I guess load/require would be closest
- You can also just evaluate a single form (e.g. a function definition) leaving everything else intact
- if you're using something like Component for state management, then you never restart the repl, just stop the system, refresh your repl state and start the system again - closest thing to 'refresh on request' from Rails' dev mode or PHP, but without the nasty surprises
The drawback is that restarting a repl is a slow process, but it's something you do very rarely. Some folks keep their repl process around for weeks.
I'd disagree - my team migrated from running containers on VMs (managed via Ansible) to ECS + Fargate (managed by Terraform and a simple bash script).
It wasn't a simple transition by any means, but one person wrapped it up in 4 weeks - now we have 0 downtime deployments, scaling up/down in matter of seconds, and ECS babysits the containers.
Previously we had to deploy a lot of monitoring on each VM to ensure that containers are running, we get alerted when one of the application crashed and didn't restart because Docker daemon didn't handle it etc etc.
Now, we only run stateless services, in a private VPC subnet, Load balancing is delegated to ALB, we don't need service discovery, meshes etc. Configuration is declarative, but written in much friendlier HCL (I'm ok with YAML, but to a degree).
ECS just works for us.
Just like K8S might work for a bigger team, but I wouldn't adopt it at our shop, simply because of all of the complexity and huge surface area.
An application usually has one connection, and many channels. Our pattern is to dedicate one channel for all publishing and then N channels mapped to consumer threads.
You don't have to pool connections as channels are multiplexed by them.
Things to watch out for:
- opening too many channels - these map to Erlang processes and can overwhelm your server if you go over ulimits
- sharing consumer channels between threads - you might see weird behavior (e.g. acking wrong messages etc)
We've built own library/framework for creating resilient consumers, and it enforces mapping 1:1 channels and consumer threads, as well as automatic reconnections and channel clean ups.
+1 for everything that's been said. Another thing to consider is message throughput, if that's a concern. In the case of multiple channels per single connection, note that a connection is a single TCP connection such that multiple channels contend for the TCP stream. At the same time, connections aren't completely free either.
The general takeaway from this should be: if you've got a particular stream of messages (either a producer or a consumer) that pushes many thousands or even tens of thousands of messages per second, use a separate TCP connection. For anything else that is slower (dozens of messages per second), multiple channels on the same connection work great.
One last consideration is that when a given channel misbehaves or you perform an operation that the broker doesn't like, the only recovery that I've seen is to shut down the entire connection which can affect others channels on the same connection.
Now up and down arrows will search your history with whatever you already have typed at the prompt. Re-running a command often? Probably just have to type its first letter and hit up arrow once or twice.
I'm not sure to be honest, I've been working with Clojure for 5 years now, and the only "help" I get from the editor I get is "highlight matching pair". I never got used to automatic paren insertion or things like paredit.
To build on what yogthos writes here, Paredit was an absolute game changer for me. The ability to edit your code as a tree structure rather than just a sequence of characters lets you do many kinds of edits far faster than is possible in non-parentheses-laden languages.
The following are all a single key combination in most editors that support Paredit or equivalents:
- Kill an entire loop or data structure to the right of the cursor
- Swap two deeply nested expressions to the left and right of the cursor
- Absorb ("slurp") or expel ("barf") expressions to either side of your current expression, into that expression
- Delete the entirety of the expression enclosing where your cursor is, leaving everything to the right intact but raised to the enclosing level (this one is amazingly common but you would never think to use it until someone shows it to you, after which you use it every day)
It takes a couple of days to get these and many other shortcuts into your fingers, after which it's hard to live without them. http://emacsrocks.com/e14.html is a good introduction.
Structural editing is the first thing I miss going back to Python, Ruby, JavaScript, etc. That, and, of course, instant REPL evaluation of the expression under my cursor.
I really recommend just forcing yourself to use it for a week or so. You just have to switch your mindset to the opening paren being a control character for starting an expression. I just don't look at the parens at all when I work with Clojure.
The document mentions using Raft for consensus and coordination - it's the same approach used by Etcd, Consul, Serf, RethinkDB and other systems. AFAIK it's easier to implement and understand than Zookeeper's consensus solution.
I don't know. First, there may be some separation achievable - but I'm just guessing. Second, if Kafka is your primary workload, you don't want it to misbehave in any case. But of course I get your point. I'm just saying I've seen people thinking about it that way in some Github Issues.
It's a very fast Scheme implementation, compiles to C and has a pretty decent [library ecosystem](http://eggs.call-cc.org/5/).
I've used it to build service monitoring daemons and various utilities. As of version 5 Chicken supports static compilation and can produce a single-file binary, which makes it super handy for a lot of use-cases.