off-topic

https://github.com/clojurians/community-development/blob/master/Code-of-Conduct.md Clojurians Slack Community Code of Conduct. Searchable message archives are at https://clojurians-log.clojureverse.org/
emccue 2020-10-10T00:00:40.221100Z

so just (.close borrowed-client) and nothing else?

emccue 2020-10-10T00:02:26.221500Z

interestingly it all works if I just get rid of the while true

emccue 2020-10-10T00:02:42.221800Z

;; ----------------------------------------------------------------------------
(defn create-pub-sub-listener
  "Creates a listener for pub-sub messages. Borrows a connection
  from the pool and doesn't return it until it is shut down."
  [pool]
  (let [client ^Jedis (.getResource pool)
        logic (proxy [JedisPubSub] []
                (onMessage [channel message]
                  (log/info :channel channel :message message)))
        executor ^ExecutorService (Executors/newSingleThreadExecutor)]
    (.submit
      executor
      (reify Runnable
        (run [_]
          (.subscribe client
                      logic
                      ^{:tag "[Ljava.lang.String;"}
                      (into-array String [post-notification-channel])))))
    {:borrowed-client client
     :pub-sub logic
     :executor executor}))

;; ----------------------------------------------------------------------------
(defn shutdown-pub-sub-listener!
  [pub-sub-listener]
  (let [{:keys [borrowed-client pub-sub executor]} pub-sub-listener]
    (.shutdownNow executor)
    (.unsubscribe pub-sub (into-array String [post-notification-channel]))
    (.close borrowed-client)))

emccue 2020-10-10T00:03:02.222300Z

but this means that any tasks I do based on messages better not fail

emccue 2020-10-10T00:04:39.223100Z

since it would stop consumption of messages

2020-10-10T00:04:45.223600Z

yeah, because the try/catch is inside the while it just creates the subscription again after you unsubscribe

emccue 2020-10-10T00:04:46.223700Z

and I would have no way to know

emccue 2020-10-10T00:05:06.224300Z

but I don't get a log of the exception when I unsubscribe

2020-10-10T00:05:07.224600Z

you can instead of (while true ), use an atom

emccue 2020-10-10T00:05:29.225100Z

so it doesn't seem like anything is thrown

2020-10-10T00:05:33.225300Z

it is likely a InterruptedException or wrapped in one

emccue 2020-10-10T00:06:04.226100Z

(while true
            (try
              (.subscribe client
                          logic
                          ^{:tag "[Ljava.lang.String;"}
                          (into-array String [post-notification-channel]))
              (catch InterruptedException e
                (throw e))
              (catch Exception e
                (log/error ::jedis-pub-sub-error e
                           ::action-to-take "retry subscription")))))))

emccue 2020-10-10T00:06:09.226400Z

i wouldn't think so

emccue 2020-10-10T00:06:25.227200Z

since in both cases there should be some observable side effect

2020-10-10T00:06:27.227300Z

it may not throw any exception

2020-10-10T00:07:00.227800Z

so (while @whatever ...

2020-10-10T00:07:20.228500Z

and (reset! whatever false) on shutdown

emccue 2020-10-10T00:07:36.228800Z

yeah but subscribe is already an infinite loop within itself

2020-10-10T00:07:55.229300Z

the unsubscribe will stop it

2020-10-10T00:08:05.229600Z

and you will stop the while

emccue 2020-10-10T00:08:06.229700Z

and even adding a log to the interupttedexception case doesn't show anything

2020-10-10T00:08:18.230Z

add a log after the subscribe call

2020-10-10T00:08:24.230200Z

or in a finally

2020-10-10T00:08:35.230500Z

what is happening is the subscribe call isn't throwing

2020-10-10T00:08:40.230700Z

just returning

2020-10-10T00:08:45.230900Z

and you loop around

emccue 2020-10-10T00:09:49.231100Z

ahhhh that makes sense

emccue 2020-10-10T00:09:54.231300Z

yep thats whats happening

emccue 2020-10-10T00:11:12.231500Z

yep that did the trick

emccue 2020-10-10T00:11:19.231800Z

;; ----------------------------------------------------------------------------
(defn create-pub-sub-listener
  "Creates a listener for pub-sub messages. Borrows a connection
  from the pool and doesn't return it until it is shut down."
  [pool]
  (let [client ^Jedis (.getResource pool)
        logic (proxy [JedisPubSub] []
                (onMessage [channel message]
                  (log/info :channel channel :message message)))
        executor ^ExecutorService (Executors/newSingleThreadExecutor)]
    (.submit
      executor
      (reify Runnable
        (run [_]
          (let [completed (atom false)]
            (while (not @completed)
              (try
                (.subscribe client
                            logic
                            ^{:tag "[Ljava.lang.String;"}
                            (into-array String [post-notification-channel]))
                (catch Exception e
                  (log/error ::jedis-pub-sub-error e
                             ::action-to-take "retry subscription"))
                (finally
                  (reset! completed true))))))))
    {:borrowed-client client
     :pub-sub logic
     :executor executor}))

emccue 2020-10-10T00:11:35.232200Z

still open question marks on the multi threaded behavior of calling unsubscribe

emccue 2020-10-10T00:11:55.232600Z

but this should only happen in dev so it won't matter that much

emccue 2020-10-10T00:12:47.232800Z

...hopefully

2020-10-10T00:28:35.233400Z

The finally there means the while loop will never loop

2020-10-10T00:29:28.235Z

Also if you want the while there you likely need to move the get resource call inside the while, otherwise if the connection dies you'll never get a new one

emccue 2020-10-10T01:02:48.235500Z

;; ----------------------------------------------------------------------------
(defn create-pub-sub-listener
  "Creates a listener for pub-sub messages. Borrows a connection
  from the pool and doesn't return it until it is shut down."
  [pool]
  (let [client ^Jedis (.getResource pool)
        logic (proxy [JedisPubSub] []
                (onMessage [channel message]
                  (log/info :channel channel :message message)))
        executor ^ExecutorService (Executors/newSingleThreadExecutor)]
    (.submit
      executor
      (reify Runnable
        (run [_]
          (let [completed (atom false)]
            (while (not @completed)
              (try
                (do (.subscribe client
                                logic
                                ^{:tag "[Ljava.lang.String;"}
                                (into-array String [post-notification-channel]))
                    (reset! completed true))
                (catch Exception e
                  (log/error ::jedis-pub-sub-error e
                             ::action-to-take "retry subscription"))))))))
    {:borrowed-client client
     :pub-sub logic
     :executor executor}))

emccue 2020-10-10T01:03:01.235900Z

yep so if it exits normally, thats another thread calling unsubscribe

emccue 2020-10-10T01:03:10.236200Z

otherwise its an exception

2020-10-10T01:10:09.237500Z

You still have the issue of that while loop continuing to try on a dead connection

emccue 2020-10-10T01:14:52.237800Z

yeah, but there are only like 8 connections in the pool

emccue 2020-10-10T01:15:14.238300Z

if i keep getting new ones i will mess up pushing other stuff to redis

emccue 2020-10-10T01:15:33.238500Z

the real issue is visibility

emccue 2020-10-10T01:15:54.239Z

like, if i could know that i messed up handling and shut down and restart this component

emccue 2020-10-10T01:16:33.239700Z

or if i had it in my dashboard (i'm using heroku for everything right now) then I could manually handle it

emccue 2020-10-10T01:16:52.240100Z

idk - i just don't want to do this in a "bad" way

emccue 2020-10-10T01:17:06.240400Z

maybe for this component i shouldn't touch the pool at all

emccue 2020-10-10T01:17:21.240800Z

and just give it its own Jedis it recreates on failure

2020-10-10T01:24:15.241700Z

The pool isn't limited to the same N connections

2020-10-10T01:24:46.242800Z

I believe when you return a connection to it, it tests it and if it is bad it throws it away and adds a new one to the pool

emccue 2020-10-10T02:30:44.243400Z

stateful things are always nightmares

2020-10-10T02:39:20.244100Z

the structure of this in our code at work looks something like this using core.async:

(async/go-loop []
  (async/alt!
    exit ([_] ...)
    (get-connection redis-pool) ([connection]
                                 (async/alt!
                                   (async/thread
                                     (try
                                       (.subscribe connection ...)
                                       (finally
                                         (close-connection connection)))) ([_] (recur))
                                   exit ([_]
                                         (.unsubscribe connection ...)
                                         (close-connection connection)
                                         ....)))))

borkdude 2020-10-10T13:05:30.245500Z

Are there any libraries (e.g. on top of rewrite-clj) that can merge EDN files and write back to a file, while preserving order / whitespace / comments etc? Maybe I'll have to write my own, but just asking in case there's already one

đź‘Ť 1
borkdude 2020-10-10T13:06:58.246Z

The use case: I want to write a package manager, but both the user and the package manager should be able to put stuff in an .edn file

borkdude 2020-10-10T13:07:07.246200Z

Kind of like npm does this with package.json

borkdude 2020-10-10T13:09:54.246700Z

I guess npm has it easier since comments aren't allowed in JSON, but still, it seems to preserve some of the user-defined order in maps

2020-10-10T13:25:46.249600Z

order is relatively easy to preserve, but only if you tweaked the reading code to use something like the ordered library https://github.com/clj-commons/ordered as long as you were then also careful about what operations you did on those maps so the ordering wasn't lost (e.g. select-keys I think always returns a built-in Clojure unordered map, so you would need to avoid using that, and/or write your own variant that returned the type of map it was given. The same goes for many other core functions on maps).

2020-10-10T13:26:10.250400Z

preserving white space and/or comments is a special purpose reader that only a few libraries implement, like rewrite-clj.

2020-10-10T13:26:51.251100Z

I suspect it would be less work to take a library that already preserved whitespace and comments, and add preservation of map/set order, than vice versa.

borkdude 2020-10-10T13:27:49.252200Z

if I would drop the comments/whitespace requirement, ordered maps could work. not sure if I can read ordered maps from plain edn maps or if I'll have to represent them using an ordered coll in .edn with a reader tag, which is kind of ugly

2020-10-10T13:29:11.252900Z

I think it would be a fairly small change to something like tools.reader lib to make it return ordered maps/sets, rather than the core unordered maps/sets.

borkdude 2020-10-10T13:29:57.253800Z

yeah, I think I could also support it in edamame (which is already built on top of tools.reader)

2020-10-10T13:30:08.254100Z

I haven't dug into rewrite-clj, but perhaps it already maintains order, but perhaps it does so by not returning regular Clojure data structures, but a custom one representing the sequence of 'things' in the input file?

borkdude 2020-10-10T13:30:18.254300Z

that's correct

borkdude 2020-10-10T13:30:35.254700Z

and writing merge, update-in, etc on top of that is a lot of work

2020-10-10T13:31:30.255500Z

Attempting to preserve white space/comments, and returning data that one can do regular Clojure data manipulation on, sounds like magic.

borkdude 2020-10-10T13:31:57.256300Z

can be done, I think. Just a lot of work

2020-10-10T13:32:09.256600Z

or writing your own custom implementation of those data manipulation functions on new data structures that contain representations of the white space/comments?

dominicm 2020-10-10T14:04:40.257400Z

@borkdude I tried this. It's called ednup. I used it in a couple of little things.

dominicm 2020-10-10T14:05:02.258100Z

I suspect your deep rewrite-clj knowledge will give you a better implementation here

borkdude 2020-10-10T15:28:45.259800Z

I guess this could become useful pretty quickly to update deps.edn files, fixing some stuff like unqualified symbols

dominicm 2020-10-10T15:30:10.260900Z

I wrote it for deps, yah. I have an alternative tag resolver that preserves comments.

dominicm 2020-10-10T15:31:19.262Z

Something I handled btw, was detection for that thing people do where they align their keys. That was feedback I got a lot of :)

tio 2020-10-10T16:19:14.262200Z

In one of my commits I accidently deleted a file; how do I tell git that I want this file? I read the instructions for `git ammend` — you basically choose a commit and git will rebase on top of it. However; I’m unsure how to add back a file. This is not an Clojure question; but I didn’t know where else to go;

2020-10-11T08:41:09.276700Z

@tiotolstoy check "git reflog" on internet, you will get your previous branches back. They are still in your repository.

tio 2020-10-12T00:42:09.288700Z

It wasn’t in gitrefleg. I had to find it in the dangling commits.

tio 2020-10-12T00:42:14.288900Z

I used the git reset HARD command.

tio 2020-10-12T00:42:38.289100Z

Anyway, thank you all for all your help. This was very informative for me. I will not use git commands without knowing exactly what they do 🙂

Thomas Harned 2020-10-13T01:10:20.302200Z

Shooting yourself in the foot with git is a software engineering right of passage. This Summer I accidentally nuked all of my Intern’s work one week before he was to present it. I was up until midnight on a Friday reading git documentation. I was eventually able to recover it after about 5 tense hours. Likewise, I no longer copy/paste git commands without understanding what’s going on under the hood.

👆 2
2
tio 2020-10-13T06:35:53.303200Z

WOW!

tio 2020-10-13T06:36:05.303400Z

What did you say to the intern when you realized what you did?

tio 2020-10-13T06:36:20.303600Z

Were you calm and collected; did you tell your superior? That’s amzing story.

Thomas Harned 2020-10-13T21:23:36.319800Z

Fortunately it happened late on a Friday so everyone was already signed off for the weekend. I sent an email that there was an “issue” I was working to resolve and left it at that. After I fixed it, I told them the whole story on Monday and everyone had a good laugh at my expense.

tio 2020-10-13T22:03:42.320Z

Ah. 🙂

tio 2020-10-13T22:03:45.320200Z

Good story!

phronmophobic 2020-10-10T16:24:04.262400Z

I probably wouldn't rewrite history if you don't have to. I would probably do something like:

git checkout <commit-where-file-exists> -- <filepath>
and then commit as normal

đź’Ż 1
tio 2020-10-10T16:27:20.262700Z

It’s 2 commits backwords

tio 2020-10-10T16:27:28.262900Z

Will it keep all of my changes

2020-10-10T16:34:46.263100Z

If you want to be really really safe about it, you can make a second clone of your repository elsewhere, do 'git checkout <commit-where-file exists>' in that copy, copy the file you want into your working repository, and do 'git add <filename>' in your working repository. Then delete the other copy of the repository if you don't need it any more.

2020-10-10T16:34:57.263300Z

Crude, but effective, and harder to mess up your working repo's state

phronmophobic 2020-10-10T16:35:54.263600Z

my suggestion works even if the file is two commits backwards and it will keep all your changes

2020-10-10T16:35:56.263800Z

I do not know off hand whether that technique will let you do 'git blame' on that file and see its entire history since it was first created, or not.

phronmophobic 2020-10-10T16:37:09.264200Z

my guess is that it won't let you do git blame all the way backwards

Thomas Harned 2020-10-10T16:41:10.268800Z

@smith.adriane is giving you solid advice here. If you really want to really want to put your mind at ease, check out the chapter on branching in the pro git book. At the risk of oversimplifying, a branch is just a pointer to a commit. So by checking out an earlier commit, all you’re really doing is pointing to an earlier snapshot of your work. Nothing is being deleted or erased. https://git-scm.com/book/en/v2

phronmophobic 2020-10-10T16:42:26.269100Z

the command I gave doesn't actually do a full checkout of the whole commit. it only gets the version of &lt;filename&gt; from that commit and stages it

phronmophobic 2020-10-10T16:43:22.269300Z

git checkout is overloaded and can do a bunch of different things

tio 2020-10-10T16:46:35.269500Z

Ah!

tio 2020-10-10T16:46:45.269700Z

So this git checkout 183ca537 -- apps/admin_web/lib/admin_web/templates/layout/_sidebar.html.eex

tio 2020-10-10T16:46:51.269900Z

Does that look OK to you?

đź‘Ť 1
phronmophobic 2020-10-10T16:48:06.270200Z

for reference, the fancy way to fix your issue and preserve git blame is to use git interactive rebase, but I wouldn't recommend doing that unless you feel confident in your git fu

phronmophobic 2020-10-10T16:48:36.270400Z

the git-scm book that @thomas.harned linked is really good and I would recommend reading it even if you don't use git

tio 2020-10-10T16:49:47.270600Z

That worked, thank you!!! Saved me a lot of frustration and hours of work.

🦜 1
🎉 1
tio 2020-10-10T17:03:54.271200Z

This deleted all of my work….

1
tio 2020-10-10T17:07:14.271500Z

I did the commmand above

tio 2020-10-10T17:07:35.271700Z

I did this and then git push forced

phronmophobic 2020-10-10T17:09:24.271900Z

if you're the only one working on the repo, that should not have required a force push

phronmophobic 2020-10-10T17:09:30.272100Z

since it only added a new commit

phronmophobic 2020-10-10T17:10:38.272300Z

force pushing is almost never required

tio 2020-10-10T17:12:25.272500Z

Fuck; ok thats my fault.

tio 2020-10-10T17:12:27.272700Z

Thank you.

tio 2020-10-10T17:12:35.272900Z

I’m not the only one on the repo;

phronmophobic 2020-10-10T17:13:50.273100Z

well, the good news is that someone else likely has the commits that were overwritten and it's likely they can recover them

borkdude 2020-10-10T18:46:48.273700Z

@dominicm Fully qualify dep symbols in deps.edn: https://github.com/borkdude/rewrite-edn#examples

borkdude 2020-10-10T19:27:58.274200Z

Also added example of adding dependency: https://github.com/borkdude/rewrite-edn#add-dependency