Sunday, May 16, 2021

(not) Auto Vapor Restart

 I was thinking it might be fun to have auto restart of Vapor, like you can do with NodeJS. But then I thought more about what happens when you need to change multiple files, and you make change after change, and it won't build & run until you've made all of the changes.

Anyway, if you add this to routes.swift:

app.delete("kill-switch") { (req: Request) -> Response in
    exit(0)
}

And you start the server like so:

$ while true ; do vapor run ; sleep 3 ; done

Then you can restart it using curl or Postman or (if you use app.get) your browser:

$ curl -s 'http://localhost:8081/kill-switch' -X DELETE

Wait, what about reloading the page when the server restarts? That should be doable, right?

Friday, May 14, 2021

Vapor 4 and MySQL

tldr; if you get connection reset/connection refused errors, try using unixDomainSocketPath instead of hostname.

I've had a heck of a time connecting Vapor 4 to MySQL. I know, maybe I should be using PostgreSQL, but I've got this old database I'd like to be able to connect to and provide new functionality with Swift code.

So I put this code in configure.swift on Linux:

    app.databases.use(.mysql(
            hostname: "localhost",
            username: "dbuser",
            password: "passW0rd",
            database: "whichdb",
            tlsConfiguration: .forClient(certificateVerification: .none)
    ), as: .mysql)

and that worked great.

But connecting to my Linux system is sometimes a pain in the neck, but it turns out that for some reason I have the same database on my Mac. I connect from the command line and `show tables;` lists every table I have on the Linux database. So copy the project to the Mac and `vapor run migrate` (because I'm going to play with the galaxies sample) and I get this error:

connection reset (error set): Connection refused (errno: 61)

Well to make a long story short, I ran lsof and saw that mysqld was listening on port 3306 but also had the file /tmp/mysql.sock open. Then I knew what to search for, and discovered that there is indeed an option to connect by socket:

    try app.databases.use(.mysql(
            unixDomainSocketPath: "/tmp/mysql.sock",
            username: "dbuser",
            password: "passW0rd",
            database: "whichdb"
    ), as: .mysql)

So basically you replace hostname with unixDomainSocketPath and you don't need the TLS configuration nonsense. Oh, and that init throws, so add try.

Hope this helps somebody!