portal

seancorfield 2023-04-16T21:29:00.083319Z

Documents my dual Portal window setup in VS Code.

2
♥️ 2
DenisMc 2023-04-21T18:47:29.930319Z

Hi Sean, quick question on your setup if you wouldn’t mind. I see that you occasionally jack in to production environments, which could be super useful in certain circumstances. I’m set up to do that as well for our prod env, but I never do it because I’m terrified that through the misapplication of muscle memory I’ll screw something up. For example, if I was to connect to a prod system using a socket repl which was loaded in my IDE (I use cursive), I could unintentionally reload namespaces into prod by triggering my usual reload key sequence - just because I do it all the time when developing. Are there techniques or conventions you use to minimise such risks?

seancorfield 2023-04-21T19:02:34.296289Z

@denis.mccarthy.kerry For starters, I have no "reload" workflow -- and I generally advocate strongly against using such things 🙂 But, yes, connecting a REPL to production carries the risk of blowing up your production system in all sorts of ways -- just as having a live connection to your production database can be perilous. I have a particular namespace that I work in when I connect to production. It contains a little bit of setup code and, specifically, sets up a readonly datasource that I can safely use for any interactions that access the database. Our production JARs are AOT-compiled with direct linking which also limits the "damage" you can do by (accidentally) redefining things since the calls sites are not automatically updated and you have to be explicit about those redefinitions up the call tree. Our deployment pipeline is sufficiently fast and easy to work with that making a local fix and having it go through CI and on to production isn't a big deal.

DenisMc 2023-04-21T19:20:47.224709Z

Thanks Sean, very useful. When you say you don’t have a reload workflow, what do you do when you are actively developing? As I write functions, I typically test them in a rich comment block, and once I’m happy with them I will load the namespace into my REPL (using an IntelliJ shortcut) and give the function a quick once-over in situ. Your recommendation against reloading namespaces would go against this if I understand you correctly. If I do understand correctly, how do you manage this aspect of the workflow? Feel free to tell me to rtfm if you’ve blogged about this piece elsewhere! On a related point, I’m curious about whether you go straight to production with fixes or do you have a manual step before code hits users? We have a deployment flow that could support either, and I haven’t made up my mind about the wisest policy here.

seancorfield 2023-04-21T19:25:20.045669Z

I eval code changes into a running REPL. Period. No "reloading". Nothing destructive. As for fixes going to production, when we commit (or merge) a change to our main branch, CI runs incremental tests (via Polylith) and builds JARs for any changed services/processes and automatically deploys those to staging, and from there we select artifacts to automatically deploy to our production cluster.

👍 1
djblue 2023-04-18T16:15:57.705829Z

I put up https://github.com/seancorfield/vscode-calva-setup/pull/3 which should enable the dual window setup when connecting with the remote-repl

seancorfield 2023-04-18T17:29:09.038519Z

@djblue I'm not sure that fits my usage. I have Portal running as a headless HTTP server in the remote processes, when they boot up. But I'll experiment with the setup at some point, probably after Conj.

👍 1
djblue 2023-04-18T17:38:16.899089Z

Running headless (starting the server on a fixed port) shouldn't conflict with this approach. This should enable calling (portal.api/open {:launcher :vs-code}) on the remote repl and getting it to open a vscode tab locally

seancorfield 2023-04-18T18:02:22.543409Z

Good to know. Thanks. And I need the very latest Portal, for this to work, right?

djblue 2023-04-18T18:17:03.842829Z

No, this should work with any version since the port mapping is being done manually via the ssh command 👌

seancorfield 2023-04-18T19:37:49.913139Z

Ah, OK. And why -R for the extension port?

seancorfield 2023-04-18T19:37:58.162159Z

(the others are all -L)

djblue 2023-04-18T19:40:15.287829Z

That will proxy the extension port from your local machine to the remote server so the portal runtime code can communicate with the extension.

djblue 2023-04-18T19:40:47.298509Z

This way all the code can pretend it's on the same box

seancorfield 2023-04-18T19:42:09.262239Z

Right, but the other ports are proxied via -L -- I was asking why the extension port uses -R instead.

djblue 2023-04-18T19:43:08.093069Z

I thought L was from remote to local and R was local to remote

seancorfield 2023-04-18T19:43:17.073919Z

Oh... direction... I had always thought of the forwarding as bidirectional...

djblue 2023-04-18T19:43:45.324069Z

It might be, not sure 🤔

djblue 2023-04-18T19:46:30.712099Z

I found this info here https://www.ssh.com/academy/ssh/tunneling-example#remote-forwarding

👍🏻 1
seancorfield 2023-04-18T19:47:36.647839Z

I'll save any other Qs until I've actually tried this! 🙂

👍 1
seancorfield 2023-04-18T20:54:13.651549Z

OK, I had a bit of "down" time over lunch to test this: works great! Thank you! My old setup (which you hadn't seen, since it isn't in that repo), assumed I would add-tap/remove-tap so there was no Portal attached to the QA/production process unless I was actively debugging... It's not a big deal since we rarely leave tap> calls in deployed code but it is something I might have to think about since those tap> calls would send data to Portal, which would continue to conj them into the results array... I can of course manage that by adding code to my custom submit to limit history... Overall, tho', it is so slick to be able to do ctrl+alt+b q and then ctrl+alt+space p and have it start the tunnel, connect to the remote nREPL, then fire up Portal in VS Code and have it connect and run "just like dev"!

2
🎉 2
seancorfield 2023-04-18T20:54:29.401749Z

q for QA, I also have p for production 🙂

djblue 2023-04-18T20:58:12.551549Z

That's awesome! Thanks for taking the time to test it out thanks3

seancorfield 2023-04-18T21:01:28.137869Z

I don't think I actually need to start the Portal HTTP server in the remote server since the code I eval launches it -- but that does beg a question of if/when that Portal server would shutdown? I guess I'm also thinking, when does .portal/vs-code.edn get a different port number?

djblue 2023-04-18T21:05:52.551089Z

I think calling portal.api/close with no args will close all UI instances and shutdown the server. The edn file should mirror the info for your local vscode instance, so anytime you restart vscode it would need to change, but that should be automatically happening currently.

djblue 2023-04-18T21:08:16.653649Z

Having a clean up function should be as easy as calling close and removing all tap handlers 🤔

seancorfield 2023-04-18T21:09:00.791849Z

Hmm, I eval'd (p/close) and it seemed to shut things down -- but now I can't get it to start back up...

djblue 2023-04-18T21:10:04.797139Z

My guess would be it might have started back up on the wrong port

seancorfield 2023-04-18T21:10:31.918149Z

I get the Portal window open in VS Code but it has no content. I did not restart VS Code.

djblue 2023-04-18T21:11:39.963979Z

I think you might need to specify the :port in portal.api/open or portal.api/start

seancorfield 2023-04-18T21:12:10.238529Z

Ah, ok... and that's the one from the vs-code.edn file?

seancorfield 2023-04-18T21:12:35.197739Z

I thought it was supposed to pick that up automatically?

djblue 2023-04-18T21:12:59.755559Z

The port for the server on the jvm, I hate how many ports are involved here lol

djblue 2023-04-18T21:13:46.047869Z

You will also need to re-shutdown the jvm runtime server if it's bound to wrong port with portal.api/close

djblue 2023-04-18T21:14:28.206559Z

(portal.api/close) (portal.api/open {:port portal-port})

seancorfield 2023-04-18T21:16:35.778859Z

So the port I was starting the Portal server on was 7311, and it needs that port and it needs the one from vs-code.edn essentially?

djblue 2023-04-18T21:17:23.498499Z

Yes. However, the vs-code.edn one you shouldn't have to worry about

seancorfield 2023-04-18T21:17:34.540809Z

Now, I call open twice in my (client-initiated) Portal code -- once for logging/middleware output and once for plain tap> -- so I called open three times in total...

seancorfield 2023-04-18T21:18:31.648279Z

The startup open specifies port 7311 but the subsequent open calls do not specify a port -- so am I correct that once it starts on port 7311, the subsequent open calls reuse that?

djblue 2023-04-18T21:18:53.263399Z

Yup, that's correct

djblue 2023-04-18T21:19:52.729889Z

If the server has already started, if just goes ahead and uses. Otherwise when starting the server it will use the provided port or a random one.

djblue 2023-04-18T21:20:44.233349Z

It's one of those things where it mostly works when everything is local and you don't care about port mapping... but when you care it sucks 😆

seancorfield 2023-04-18T21:21:59.642789Z

OK, I recovered it! I did (p/start 7311) and that (re)started the http-kit server on the correct port.

seancorfield 2023-04-18T21:22:12.851619Z

So calling (p/close) is pretty dangerous...

djblue 2023-04-18T21:23:48.938539Z

Do you mean (p/start {:port 7311})? I would say delicate, but easily fixable

seancorfield 2023-04-18T21:24:09.308119Z

Yes, sorry, that's what I meant.

👍 1
djblue 2023-04-18T21:26:20.284309Z

I think perhaps start / open could indicate / print something if the server is already started and on another port to help aid in debugging

seancorfield 2023-04-18T21:27:21.638749Z

So I really only want to close the new interactive instances I open'd in my VS Code session for debugging things... luckily, I do save both of those in a dev namespace...

djblue 2023-04-18T21:29:12.622279Z

(defn close [portal]
  (if (= portal :all)
    (c/request {:op :portal.rpc/close})
    (c/request (:session-id portal) {:op :portal.rpc/close}))
  (when (or (= portal :all) (empty? @c/connections))
    (future
      (some-> server deref :http-server http/server-stop!)
      (reset! server nil)))
  (swap! rt/sessions dissoc (:session-id portal))
  (swap! rt/sessions select-keys (keys @c/connections)))

djblue 2023-04-18T21:29:28.939799Z

I think portal still might kill the server if you have no clients when you call close

djblue 2023-04-18T21:30:39.470119Z

If you are cool keeping the server running, killing the tabs in vscode is probably the way to go

seancorfield 2023-04-18T21:31:00.114389Z

Yeah, I think that's fine.

👍 1
djblue 2023-04-18T21:33:41.701249Z

However, maybe adding a explicit portal.api/stop would be better here 🤔 then I would remove the auto shutdown, feels more confusing than its worth.

djblue 2023-04-18T21:34:32.335429Z

It's also more symmetric, start/stop open/close

seancorfield 2023-04-18T21:35:22.719629Z

I restarted VS Code, reconnected to QA, and started Portal again with my regular command sequence and it worked, using the different port from vs-code.edn

seancorfield 2023-04-18T21:35:55.434729Z

Where is that c/connections var? I want to see how many sessions it thinks it has now...

seancorfield 2023-04-18T21:36:38.210079Z

Found it...

👍 1
seancorfield 2023-04-18T21:39:11.659539Z

Confirmed that when I close each VS Code window, that connection goes away in the connections atom. When they're all closed, the atom is empty -- but the server stays running at that point -- and I can shutdown VS Code, restart it, and reconnect just fine... so it's all good at this point.

👍 1
seancorfield 2023-04-18T22:15:02.874529Z

My dev setup for daily work -- my logging/middleware output window and my regular tap> window have different themes 🙂

💯 1
1
🎉 1
seancorfield 2023-04-18T22:18:11.813589Z

And now my remote setup is near identical 🙂

djblue 2023-04-18T22:28:47.502299Z

I wonder if I should add vscode theme variants, so it can match but be different 🤔

seancorfield 2023-04-18T22:41:36.597699Z

I think that would be overkill 🙂

djblue 2023-04-18T22:44:02.193289Z

True, but it would be relatively easy and might be helpful when the default mapping doesn't work well for a given theme

seancorfield 2023-04-19T05:05:04.798159Z

I've updated my blog post to reflect the Pull Request from @djblue and the much-improved workflow that gives me -- so slick to copy .portal/vs-code.edn from the "client" machine running VS Code to the remote machine running the REPL! Thank you!

1
🚀 1