Fork me on GitHub
#off-topic
<
2020-04-03
>
hindol08:04:52

Is there a "Clojure function of the day" app somewhere? I just stumbled upon bounded-count and wondering how many more less known functions are there. An app like that can help surface such functions.

hindol08:04:21

Nice. Is there something that puts more weight on lesser known functions?

Bobbi Towers09:04:54

This was a good talk that did that: https://www.youtube.com/watch?v=QI9Fc5TT87A

👍 8
hindol09:04:20

That's great! I might make something out of it.

😃 4
sogaiu09:04:10

may be not quite what you're looking for, but someone did a graalvm native-image thing somewhat along those lines: https://github.com/tomekw/cotd

bartuka00:04:46

Using the great print-random, I added it to my emacs init scratch buffer message:

(let ((clj-docstring (shell-command-to-string "docstring.clj")))
      (when clj-docstring
	(setq initial-scratch-message clj-docstring)))
"docstring.clj" is in my PATH. Also made an interactive fn to call it and show the answer in a new buffer 😃
(defun bk/clj-random-docstring ()
      "Random doc-string into new buffer."
      (interactive)
      (let ((docstring (shell-command-to-string "docstring.clj"))
	    (buffer-name "*Clojure Random Docs*"))
	(when (get-buffer buffer-name)
	  (kill-buffer buffer-name))
	(get-buffer-create buffer-name)
	(with-current-buffer buffer-name (insert docstring))
	(switch-to-buffer-other-window buffer-name)
	(special-mode)))

souenzzo15:04:02

There is some reason to NOT deploy production apps with clojure -Sdeps "{:deps {my.comp/my-app {:git/url "" :sha ".."}}}" -m my.comp/my-app ?

mauricio.szabo02:04:50

I can think of a lot of reasons on why NOT to do 😄 - Your app needs to access git (if private, needs credentials to git into server) - Startup is slower (need to clone, compile, then there's the warmup of JVM) - You have no control over the environment (different cli / JVM versions can give unpredictable results) - You can't restrict access to internet if you deploy like this - SHAs are not absolute: a rebase / amend can remove the SHA, and its hard to understand if that SHA was before / after some version

souenzzo18:04:00

1 run clj -Stree on "build server" and store it's m2 and gitlibs, now "production server" will run offline 2 not a issue for me 3 I control everything in EC2 or K8 4 (eval *1)` 5 I trust git sha's as I trust maven signatures. I can also add a maven untrusted repo and use a bunch of untrusted jars.

mauricio.szabo19:04:34

1 - well, you're reinventing uberjar / clone the repo and run clojure cli 😄

dpsutton15:04:47

presumably you stop previous version and then run that version which involves downloading from git (if easily visible from prod) while app is down. if you create a jar the data movement happens while the previous version is still up

Ahmed Hassan21:04:23

> if you create a jar the data movement happens while the previous version is still up > What does this mean?

hiredman21:04:04

if you do the ci server approach you have different versions ready to go, you are aren't stopping the current version, hoping the new version builds correctly on every server, then starting it

dominicm15:04:35

Well, that's avoidable by doing -Stree first.

dominicm15:04:49

I don't think there's any problem with it, no.

dpsutton15:04:00

ah good catch

dominicm15:04:26

Kinda similar to loading a massive jar anyway, so most tools have a solution for loading your code first

hiredman15:04:38

I would prefer not to run dependency resolution and fetching on each node (avoid the possibility of getting different results)

hiredman16:04:21

But I think you can achieve a similar effect by using clojure on a ci server to resolve and fetch once, and push individual deps to servers (skip if already there) and then push a prebuilt classpath

👍 4
hiredman16:04:40

You get the benefits of avoiding a large single artifact and only push changes, while avoiding the pitfalls of resolving and fetching multiple times

dominicm16:04:26

Pack has code which can do that

dominicm16:04:37

It is called "skinny"

hiredman16:04:20

yeah,, basically that

Alex Miller (Clojure team)16:04:40

Some of the Datomic build stuff is similar to that

hiredman16:04:03

I saw a talk where rich discussed ions which made me want this

hiredman16:04:54

skinny + rsync + wildcards in the classpath is pretty much all of it

hiredman16:04:10

but the example code is kind of all in one, and doesn't require you to copy everything out to the on disk layout and then rsync it

hiredman16:04:28

and using wildcards in the classpath precludes some useful things, like having a single directory containing all the dependencies for multiple different versions

hiredman16:04:54

(which you really want to make the rsync thing work)

hiredman16:04:25

so ideally when you deploy you are mostly pushing just a delta

hiredman16:04:58

yeah, I take that back, you lose all the best stuff if you just cobble it together via skinny + rsync + wildcards

dominicm17:04:04

So it is mandatory to have the classpath saved exactly?

hiredman17:04:32

yes, you need that if you just want to push deltas

hiredman17:04:55

e.g. you have some directory on your server /code and are running version 1, you want to be able to rsync the new stuff over /code and then switch to version 2, and then roll back to version 1 if needed

hiredman17:04:07

so /code is sort of like git's object directory, a pile of everything, and it is the classpath files that tell you which parts of it fit together for which versions

hiredman17:04:53

so I guess the classpath files would be sort of like git refs

hiredman17:04:57

it looks like pack's skinny writes out the version from the deps.edn, which is likely good enough (in the poc I think I sha1'ed everything so versioned by file contents)

David Pham18:04:42

Is there a success story channel?

sova-soars-the-sora19:04:47

@neo2551 nice idea. there are enough to warrant a channel

dominicm20:04:42

@hiredman outputting a classpath file or a jar with a classpath entry were ideas I had but nobody asked for yet :)

hiredman20:04:57

I think it is tricky to do that independent of whatever code actually does the deploy, because the way the classpath is built will depend on how things are deployed. using relative paths works until it doesn't, and you want to java -cp cat classpath` your.main` in some other working directory for some reason

hiredman20:04:07

and I guess all the cool kids are deploying docker images and don't care about this kind of thing

dominicm07:04:57

Pack also has a mode which generates a docker image and does exactly what we are talking about with the hardcoded classpath.

Ahmed Hassan21:04:51

Isn't it good idea to clone GitHub repo at remote server, build jar file and deploy it? (Everything on server) (Using ssh shell script or #spire)

hiredman21:04:04

yes, usually that remote server is called the ci(continuous integration) server

borkdude21:04:23

Github itself supports this as well (actions)

hiredman21:04:56

the way you would usually do that is you have something like jenkins setup to monitor a git repo, when it sees changes it generates a build(often an uberjar), and then makes it available to whatever is next

hiredman21:04:30

the annoying thing with that is uberjars can be rather large, and convey a lot of redundant information for upgrades (most of your deps don't change at all between versions of your code)

hiredman21:04:37

so the idea is to always accumulate code (your code, dependencies, etc) and then a "build" is just a small text file that points into this accumulation of code to pull together all the right versions of dependencies

hiredman21:04:46

so a deployment can be just pushing whatever new code needs to be accumulated on a server, and a text file describing how to build a version out of all that accumulated code

Ahmed Hassan21:04:05

In local machine while doing development we have cached versions of dependencies on class-path, which are downloaded only on initial run of application. So, we want to have similar conditions on remote server. Right?

Ahmed Hassan21:04:56

Having dependencies co-located with the building place of application.

hiredman21:04:58

but I want to do all the resolution and download once for all servers to ensure they get the same thing

hiredman21:04:15

just like a ci server would do

hiredman21:04:17

another solution to the same problem (making deployments smaller and artifacts less redundant) that I have played with is using binary diffs

hiredman21:04:57

if I have version 1 deployed and I want to deploy version 2, I take the uberjar for version 1 and diff it with version 2, and send the diff to the servers and have them apply it

hiredman21:04:42

I didn't really get far enough with that to get a feel for how much redundant shipping around of dependencies it removes

Ahmed Hassan21:04:23

The way you are saying, we'll have to sync folder of dependencies on all servers and make sure each of them is same.

Ahmed Hassan21:04:59

I don't understand idea of diff

hiredman21:04:10

like a patch

hiredman21:04:22

given A what set of changes do you need to apply to get B

Ahmed Hassan21:04:49

So you send dependencies of diff of A and B to servers, because dependencies of A are already there. Right?

hiredman21:04:54

with diffs I was diffing the uberjars which already contain all the dependencies

Ahmed Hassan21:04:40

I don't quite understand idea of diffing ubrjars

hiredman21:04:17

just like you can diff two text files and get a patch that transforms one into the other, there are tools to do that for arbitrary binary files

Ahmed Hassan21:04:29

After that you reconcile diffed dependencies between all servers and current build. Right?

hiredman21:04:26

the uberjar contains all the deps, so by diffing uberjars the diff includes dependency changes

Ahmed Hassan21:04:00

So, you rsync or send these changes to all servers.

hiredman21:04:55

so you do something diff version1.jar version2.jar and the output is a patch file hopefully smaller than version2.jar which can be used to turn version1.jar in to version2.jar

hiredman21:04:45

you ship that patchfile to all the servers, and apply patchfile version1.jar > version2.jar then stop version1.jar and start version2.jar

hiredman21:04:14

chrome at one point was using binary diffs for updates

hiredman21:04:19

the binary diff idea is entirely different approach from what I discussed earlier in the channel, it is just intended to solve a similar set of issues

Ahmed Hassan21:04:24

This is great idea.

hiredman21:04:42

most the binary diff algorithms are tuned for executables and not jar files though, so hard to say how effective they will be there

Ahmed Hassan21:04:08

There should be java specific solutions already in existence

Ahmed Hassan21:04:24

When upgrading running application, While stopping version 1 and running version 2 of application, how do you manage time duration in between? Or do you simply drop requests for this duration?

hiredman21:04:26

that is highly app and deployment specific, but however you answer it the same answer should work for uberjars, accumulations and classpaths, or binary diffs. some answers may even help with some of the downsides of deploying right from git

Ahmed Hassan21:04:15

Running new version with different port than old one, pointing traffic to new port (Nginx) for new running version and closing old one while new one is in service. This may be one solution.

hiredman21:04:35

https://www.youtube.com/watch?v=thpzXjmYyGk&amp;feature=youtu.be is the video of rhickey that caused me to start thinking beyond uberjars(and similar things) for deployments

👍 4
hiredman21:04:43

and the deps bits is maybe 40 minutes in