Fork me on GitHub
#clojure
<
2023-11-23
>
weavejester16:11:31

I'm trying to work out the methodology behind how Clojure handles reporting uncaught chained exceptions. I'd expect that the outermost exception, the one that wraps all the others, would determine the thrown printed message, but it strangely appears to by the innermost instead. i.e. (Exception. "a" (Exception. "b" (Exception. "c"))) would print out "c", not "a".

p-himik16:11:18

It's mentioned in Throwable->map:

:cause - root cause message

weavejester16:11:36

I'm unsure why that's the way the exception is displayed, though. I'd assume the message of the outermost exception would be printed, not the message of the innermost one.

oyakushev16:11:54

Do you question how this happens or why this is the preferred way?

weavejester16:11:18

Why this is the preferred way. Presumably it's a deliberate choice.

oyakushev16:11:25

I can only guess, but in my own experience the wrapping exceptions are usually not much more than a vessel with which the innermost exception (the root cause) is delivered. Things like ExecutionException and the like.

1
oyakushev16:11:50

With that in mind, it makes sense to see the root cause foremost.

weavejester16:11:01

I guess that makes some sense. My own take was that the outermost exception has the most information. The way the error reporting works by default means that wrapping exceptions to give additional context is lost unless the user looks at the exception in detail.

weavejester16:11:24

I guess I can always build my own error reporter.

oyakushev16:11:09

Yeah, I have to agree that no two nested stacktraces are the same, and guessing which representation would serve best for a particular one is hard.

oyakushev16:11:11

Reordering things is fine, but omitting them completely is kinda meh. That's why I've never been a fan of Clojure CLI hiding errors in a file, I'd rather look at an ugly stacktrace every time.

Ingy döt Net17:11:34

How might I transform (System/getenv) into a hash-map of keyword/string pairs?

p-himik17:11:20

(update-keys (System/getenv) keyword)

clojure-spin 1
Ingy döt Net17:11:51

well that's slick!

p-himik17:11:56

(Not guaranteed to be a hash map - might be an array map if your environment is tiny).

ghadi17:11:05

(into {} (System/getenv)) is a favorite of mine, too

ghadi17:11:25

but not keywords

Ingy döt Net17:11:25

(keys (System/getenv)) worked as I expected but other things like seq did not. Is (update-keys (System/getenv) str) a good way to turn it into a map? oh ^^

Ingy döt Net17:11:40

Thanks @U2FRKM4TW and @U050ECB92 🙂 Actually for my needs I think I'll go with a str/str map, so that one is great

👍 1
Ingy döt Net17:11:31

Glad I asked here. I feel like this might have taken forever on my own. The internet was not being my friend on this.

jmckitrick17:11:42

What’s the best PAAS for free/hobby Clojure projects these days?

kwladyka10:11:36

Google Cloud Run is a winner for me

jmckitrick12:11:23

I assume these services all need docker to run Clojure, right? I think the Heroku buildpacks were the only ones that supported Clojure sort of ‘natively’?

p-himik12:11:38

I'd wholeheartedly advise to avoid buildpacks and instead rely on Docker or something similar (I myself use podman to work with OCI container, same thing conceptually).

1
jmckitrick12:11:55

There’s no question I have to move to docker… as long as I can avoid k8s. I don’t understand everyone’s infatuation with it. It’s overkill for most shops, IMHO.

jmckitrick12:11:00

I’ll check out podman

p-himik12:11:17

Indeed, you don't need to use k8s to work with containers. Nowadays, I even run npm via a container while allowing it access only the cwd. Because screw it, and it's just a single command with a few flags.

jmckitrick12:11:29

I’d like to get to that point, it just feels like an extra layer of abstraction

kwladyka12:11:38

https://cto.wladyka.eu/posts/2021/best-devops-choices/ it is a little too long but can be help to make a choice

jmckitrick13:11:23

I’ll read it right now with my morning coffee

1
jmckitrick13:11:41

Along with podman docs

jmckitrick13:11:28

@U0WL6FA77 Are there any updates to this article from 2021?

kwladyka13:11:14

I didn’t have time to write more articles after this one :(

kwladyka13:11:32

But more or less everything is up to date

👍 1
jmckitrick13:11:42

I understand. I just want to make sure I have current facts in case anything has changed.

jmckitrick13:11:01

Very good article so far

❤️ 1
p-himik13:11:23

Just as an example, here's how I run npm (this is in my .zshrc):

npm () {
	if [[ $1 == run ]]
	then
		command npm "$@"
	else
		podman run -it -e "TERM=xterm-256color" -v ./:"/root/${PWD##*/}" -w "/root/${PWD##*/}" node:slim npm "$@"
	fi
}
That's it, nothing else. And it makes NPM pretty much isolated from the rest of the system where none of its blunders can affect it (like some installation scripts deleting ~).

jmckitrick13:11:54

lol I’m not a fan of npm either, in that respect.

jmckitrick13:11:11

@U0WL6FA77 I am also looking at terraform, so I will compare

kwladyka13:11:44

In the context of terraform I did last research a few years ago. Perhaps it works better today.

practicalli-johnny13:11:35

If its a single Clojure app, i still prefer buildpacks. Most services that use build packs 'borrowed' from the ones that Heroku and community created, so they are pretty reliable. For more of a mixed stack, then Docker becomes relatively easier to use. Docker has some good docs and the learning curve is relatively low, especially when using Docker official images as a base. Docker desktop has some great tools for managing docker locally and most PaaS should be able to run a docker image quite easily. Using a multi-stage Dockerfile configuration is highly recommended, e.g. https://practical.li/engineering-playbook/continuous-integration/docker/clojure-multi-stage-dockerfile/

kwladyka19:11:14

@U061KMSM7 Please give me feedback after all if you found my article helpful. What I could do better and what is good. Maybe you have some questions.

jmckitrick19:11:25

I was actually getting ready to work my way through some of the examples but I am on macOS so I need to do more research since your article mostly focused on Linux

kwladyka19:11:12

What do you mean by focused on Linux? I work on OS X all the time. Of course all apps are deployed in Linux. To be precise docker.

jmckitrick21:11:32

The Practicalli site is Linux-centric in general, that’s all I’m saying.

facepalm 1
kwladyka21:11:18

I see, just not sure what it means for you. This is why I asked.

kwladyka21:11:01

Feel free to give any questions. I will try to help.

jmckitrick21:11:48

I use a mac for hobbies and consulting, and also for work. I am researching using docker both for local development as well as for production deployment. At my last job, we used Scala and docker, but that was a few years ago.

jmckitrick21:11:34

Since then, a lot has changed in devops, so I want to be sure that I thoroughly research how containers are being used now, and if there are any special concerns for setting up docker for local development on our macs.

kwladyka22:11:51

In my humble opinion docker images is the only one right choice this days. Whatever you choose (docker desktop, docker compose, k8s, AWS, google cloud etc.) everything work with docker images. Saying this in other way in my opinion there is no reason to use something else while we can use docker images for everything making it very consistent. There are alternatives on the market but I see them like artifacts of the past. People were using them so they have to maintain them. Unfortunately I can’t recommend any good article to learn docker. You need to make Dockerfile like this for Clojure:

# linux deps
FROM clojure:temurin-17-tools-deps-1.11.1.1165-bullseye-slim as env
WORKDIR /app
ENV TC=UTC

# linux + clojure dependencies
FROM env as env-with-clj-deps
COPY deps.edn .
RUN clojure -P -M:test
RUN clojure -P -M:check-syntax-and-reflections
RUN clojure -P -T:build

# full image ready to compile and tests
FROM env-with-clj-deps as deps-with-code
# RUN apt install something or other commands if needed
COPY . .

# tests
FROM deps-with-code as tests
RUN clojure -T:build test

# build
FROM deps-with-code as builder
ARG VERSION
RUN clojure -T:build uber "{:version \"$VERSION\"}"

# final
FROM env
EXPOSE 80
COPY --from=builder /app/target/app.jar ./
CMD ["java", "-XX:InitialRAMPercentage=70", "-XX:MaxRAMPercentage=70", "-XX:-OmitStackTraceInFastThrow", "-Dclojure.tools.logging.factory=clojure.tools.logging.impl/jul-factory", "-jar", "app.jar"]

kwladyka22:11:27

This is for deps.edn. This will work in google cloud run, on localhost, everywhere

jmckitrick22:11:37

OK great, that is a good start. Thank you! Yes, I have several articles for refreshing myself on docker. I will just have to go back and review them.

👍 1
seancorfield22:11:37

I still run Clojure itself via the CLI "on the metal" but I use Docker for "services" locally (MySQL/Percona, Elastic Search, Redis, and a few other things). I've seen too many people bump into sharp edges with editor integration etc trying to run Clojure in a container for local dev. But there's definitely an argument in favor of reproducibility and keeping your dev system "clean" and if I worked on multiple commercial projects I'd probably be more inclined to containerize my local dev env. I think it depends on your use case / needs to some extent.

seancorfield22:11:38

(our CI pipeline is essentially containerized but our production deployments are still "on the metal" although those are managed VMs these days)

jmckitrick22:11:51

@U04V70XH6 we currently use Capistrano for deployment, but we are looking for something more like terraform. But we also have a CICD solution that we want to use for deployment if possible to reduce the workload on our team.

kwladyka22:11:24

To be clear: I don’t mean to use docker as part of developing process like editor integration etc. Writing code in editor should be done as usually.

jmckitrick22:11:03

We use brew services to run our database and elastic search and that’s it. We are up and running.

seancorfield22:11:14

@U0WL6FA77 I'm talking about where the REPL runs -- some people run their REPL in a Docker container for local dev which... 👀

kwladyka22:11:51

So far I use REPL in editor (no docker) and never feel I need something else. I agree.

jmckitrick22:11:22

I think what we are shooting for is a very easy deployment after circle CI has completed unit tests and built an image. And I believe that pretty much requires a container-based solution which I’m not crazy about because I like old-school bare metal but we have to keep up with the times lol.

seancorfield22:11:06

@U061KMSM7 We haven't felt the need for server build stuff like that: servers just need a JDK installed and a few scripts so we have the scripts part automated (with another script!) but we don't stand up new servers very often (like, once every three years maybe?) so we haven't felt the pressure to do much with it. At some point I do see us moving to ECR/ECS maybe (our frontend app already deploys that way from BitBucket Pipelines) but we just don't need that right now.

seancorfield22:11:13

Right now, a commit to master triggers a fully-automated pipeline to deploy to our QA cluster for additional testing, and then we have a dashboard in our internal admin app that lets devs or the business team push specific app artifacts up to production and that's an automated rolling process, powered by shell scripts and cron.

jmckitrick22:11:44

We deploy to Azure but one time they had a grub issue that was a major problem for us. The server had to be rebuilt by hand and terraform would’ve been wonderful at that point.

jmckitrick22:11:40

It sounds like you have a very automated point, and click or timed deployment, which is usually implemented with images in containers, but not in your case

jmckitrick22:11:11

But several years ago I worked for a start up that had fantastic devops that did exactly the same thing with chef and puppet before docker was en vogue

seancorfield22:11:39

I've been at the current place 13 years 🙂

jmckitrick22:11:54

Yes, you definitely win the gold medal for that metric

seancorfield22:11:18

Docker appeared "only" ten years ago 🙂

jmckitrick22:11:26

I believe the shop I’m referring to was 2014

seancorfield22:11:29

At this point, when the data center we use needs to move us from one location to another, they just copy the VMs with Zerto and then we power down in one place and power up in the other.

jmckitrick22:11:31

So that makes perfect sense

kwladyka22:11:42

While we are in the context of CICD in my personal opinion github actions is the most powerful choice right now. This really make a difference. It is hard to give good examples right now, but it makes workflow code smaller and easier to do. At least my numer one.

seancorfield22:11:28

For open source projects, totally agree. We're an Atlassian shop and BitBucket Pipelines is pretty good. It's not GitHub Actions good, but it's "good enough".

seancorfield22:11:05

(my open source projects used Travis CI for a while, then Circle CI, but now they're all GHA -- even Clojure/Contrib has all moved to GHA!)

jmckitrick22:11:22

That definitely says something so at this phase of the game maybe we should revisit that decision as well

kwladyka22:11:30

BTW I wish to work with you @U04V70XH6 one day :) I often read your posts and you are really clever person :) It could be really good experience :)

seancorfield22:11:00

Thank you 😊

seancorfield22:11:26

I've learned a lot of lessons from the current codebase / environment. If I was rewriting it all from scratch today, I'd do things differently 🙂

jmckitrick22:11:49

@U0WL6FA77 I am very sorry I confused your article with another link posted in this conversation :man-facepalming::skin-tone-2:

jmckitrick22:11:30

Your guide was excellent and I just need to update my knowledge of docker and research terraform and your article was very helpful

❤️ 1
kwladyka22:11:53

This explain “Linux focus” confusion. I hope it is still helpful article :)

kwladyka22:11:10

Happy to hear that

jmckitrick22:11:15

😅 yes exactly

jmckitrick12:11:46

@U0WL6FA77 How difficult is it to use docker with an M1 mac while deploying to Linux?

kwladyka12:11:27

this days it is ok, but I don’t use M1. In the past it was problematic.

kwladyka12:11:41

it should be ok as long as you use newest versions of docker images like mongodb etc.

jmckitrick12:11:57

Another idea that occurred to me is I can obviously use a docker file to build an image on my local machine for development, but then use GitHub actions to build a different image for testing and deployment

kwladyka13:11:35

Nah, just use GitHub actions to build image and make tests during it to be sure you test exactly the same.

kwladyka13:11:04

No reason to do it on your computer. It will make only additional overhead.

jmckitrick13:11:49

But isn’t that the reason to use docker locally, to make the dev experience easier?

kwladyka13:11:49

In other words it is really worth to learn GitHub actions and docker.

kwladyka13:11:19

I will answer later.. I have to afk

kwladyka13:11:23

I think I know what make confusion. You have to differ two things: 1) Dockerfile where you are in full control. This it to build in GitHub actions. Eventually you can build on localhost to test something, but this is rare use case. No M1 issue. 2) Docker compose where you setup all dependencies like database, other services etc. This one you run in you computer + usually also in cicd to test your app. Here were issues about M1 because for example database docker image didn’t work with M1 and you had to run beta version.

kwladyka14:11:12

People usually say docker for everything which can be confusing

jmckitrick14:11:59

At my last job, we had a number of separate products and services, and they were developed by different teams. So it worked out well for us to use a docker compose file so that a developer could spin up any of those other services without having to completely build the project locally. But my current job has a much smaller product and monorepo so I don’t think docker would be as much of a benefit for local development

kwladyka14:11:33

Probably you need at least database

jmckitrick17:11:44

On the other hand, maybe it only makes sense to use docker for deployment and not use docker for local development at all since the system we have now works just fine

kwladyka17:11:11

I use it everywhere where I can. It makes very consistent experience for all projects.

p-himik17:11:48

Apart from that, it also makes your environment future-proof, easy to clean, easy to migrate. E.g. suppose you work on a project that requires a specific version of PostgreSQL. You install it locally and you're good to go. But later, you get to work on another project in parallel with the first one that needs a different version. With containers, dealing with stuff like this is a no-brainer.

jmckitrick17:11:53

No performance hit or loss of transparency?

seancorfield18:11:47

There's some performance hit -- you're relying on virtualization after all -- but for local testing it would be less of a hit than reaching out to external servers/services, for example. But your local testing probably shouldn't be dependent on the performance of databases etc -- otherwise you have slow tests (we fall foul of this at work, but mostly it's an acceptable tradeoff against trying to mock out the database etc or swapping in an in-memory database etc).

p-himik18:11:31

> you're relying on virtualization after all *but only on macOS (which the OP uses, yeah)

seancorfield18:11:46

My setup is WSL2 so my Clojure REPL and files are already all on a VM 🙂 and I still use Docker on top of that for DB/search/etc 🙂 My editor is native on Windows tho'...

seancorfield18:11:28

(and I took the question to mean "is there a performance hit when using containers?" which... yeah...)

p-himik18:11:16

Ah, I was under the impression that WSL was somehow implementing the whole Linux kernel without virtualization. Containers on Linux run natively though, there's no virtualization involved at all. Unless the architecture is different, I think.

jmckitrick18:11:12

Oh, nice, because of cnames and namespaces, right?

p-himik18:11:16

*cgroups, yes, at least AFAIK.

jmckitrick18:11:06

Yes, lol I have cnames on the brain

seancorfield18:11:36

WSL1 was intended to be based on a Linux kernel "bridge" into Windows but they abandoned that for WSL2 and went for a VM. With WSL1, best performance was files on Windows, processes on the VM but that had some inherent issues (processes still wrote the Linux fs and it was slow). With WSL2, best performance is everything on the Linux VM (although the Windows fs is still accessible as /mnt volumes). It's "good enough" in nearly all situations tho' and works well with Docker (on Windows) providing services to Clojure (on Linux). Good to know that Docker on Linux can avoid virtualization -- I did not realize that: I thought Docker inherently meant VMs.

p-himik19:11:17

Ah, I see, thanks.