(Not sure if this better fits into the Web or the macOS section. Choosing macOS because it’s not necessarily related to http.)
I need to run a little internet server process that responds to queries from my various apps, in order to generate licenses.
Since this is a private protocol, I do not need to use the http-based service but would rather just run a TCPSocket listener, via a ServerSocket instance.
This means, however, that a single Xojo app has to keep running at all times on my server (which runs OSX 10.11 currently).
I am worried that this always-running app might run into troubles, such as locking up, running out of memory, or other things that creep up over time. I also need to make sure OSX restarts it whenever it crashes.
I realize that I could instead make this a CGI using Xojo’s Web target, at which point most of this would be taken care of by the web server (such as Apache).
I like to keep this lean and easy to debug, though, so I want to try this with a standalone macOS target for now.
What are your experiences with this? Any recommendations?
Thanks for digging up that old conversation, Edwin.
I do not need with writing the server itself, though. I’ve got that all working already. I like to get advice on the actual experiences with using one or the other method.
As I wrote, I’m currently using the good old TCPSocket + ServerSocket, and wonder if that’s stable enough for month-long running, or whether I should switch to using Web target’s standalone server option, even though I do not want a web server.
It does work. And as far as I know and experienced, it was pretty stable.
Also, if your service becomes rather busy, you could consider some load balancing. The first request goes to a web service that keeps track of how many users are connected to the main web server. The first service just responds with an address that points to an instance of the main web server.
In my case, I tested it with 5 instances. Whenever a new instance of the main web service was launched, it registers itself with the load balancer. The load balancer just added the address of the instance to an array.
Each time a new request came in, the load balancer increased a counter to be able to iterate through the array of addresses. It would send that address to the user’s client application. The client application would simply continue the client-server conversation with that address.
When the client is connected to the main service, the main service would send a message to the load balancer, telling it that it has a new connection. This way I made sure that the load balancer knew how many connections are active per service instance. When a connection with that service gets lost/ended or whatsoever, it would also send a message to the load balancer.
It is not needed if you don’t expect large amounts of traffic. I made this construction in such a way, that I didn’t have to worry about assigning the instances manually. Registration with the load balancer goes automatically. Worked like a charm.
I changed some things later on. I moved from an array to SQLite. This way it was easier to sort the list of the main-service addresses, by prioritizing them, in the order of some counter index and a number of current connections with clients. So, the load balancer would send the address of the main service with the least amount of connections. When multiple services were found, it would return the services that have not been used for the longest time. This way each server would get it’s turn.
Another thing I could have added was the specs of the main service’s machine to give the fastest machine a higher priority.
If you plan on making a REST-API, a Xojo web app can do a lot of the request handling.
But I was not able to install it ISP’s servers. Because they didn’t allow that kind of CGI apps.
What I wanted to do, back in the days, was making a media metadata manager. A service where any connected user could ingest raw camera footage. The server would save it at the right location, including some data I fetched from the raw video files. And, making a series of thumbnail images.
I have plans for making use of my old construction, to make a project management service. Making use of some dynamic PDF-like document… but that is still on the drawing table.
Good point about the load handling. Since Xojo apps can run on only a single CPU core at any time, high load would make the responses rather slow. I don’t expect high load, though, so in my case this is not an issue.
I’m curious, though - how did you arrange the load balancing? Did you manage it all in one app or did you then implement the services as their own processes, so that the balancer would launch a new process if the balancer is “too busy”? And if it does that, how do you pass the connection to the other process? Or would you tell your client to reconnect to the new process, which would listen in a different port number?
I couldn’t find the project. It is backed up somewhere. I don’t use it anymore. But I should dig through my backups since I plan on working with it again.
I made a separate app to deal with the load balancing. The instances could indeed run on the same machine. But also on other machines as well.
client1 > balancer: Hello I am a client
balancer > client1: Hello I am the balancer. My UTC time is 2017-10-23 11:27:40 ’ balancer looks up next available server… launching instance 5…
Of course, I make sure that I register instances with the balancer.
’ An instance is being launched.
Instance8 > balancer: Hello I am Instance8, I reside on IP address 123.456.789.012, my domain name is “instance8.domain.com”. I listen on port 1234. I did a speed test. Processing the test data only took me 0.123 milliseconds.
balancer > instance 8: Hello instance8. Welcome to the address pool. I will make note of your info. You are a fast machine. I give you a higher priority. Please, stand by to receive any client connections.
Instance8 > balancer: Sure, standing by
’ Instance8 is now waiting for a client to connect with it
When installing an instance, I could simply use a DNS service to find a domain name for that instance. I have not done that, I did enter that manually. Of course, only a simple IP address is enough. But I prefer the use of domain names. This way I only have to change the IP address at my hosting company. And not in all the apps that point to that address.
I’ve run Xojo web apps for months on end behind haproxy as a load balancer. I have 4 apps in particular that I run on a mac mini server behind haproxy that I hardly ever reboot except for updates.
Regardless of whether you run your app as a xojo web app or a tcpsocket based regular mac app, I would definitely recommend haproxy to help you maintain uptime and reliability. There is more info on the forum if you search for it.
Ahh, LaunchDaemons. Those demons that I keep mispelling as deamons.
And thanks, Edwin, for explaining your load balancer. So it requires the client to open a new connection. That’s easy enough, but I had hoped I’d learn a trick how to do that without a reconnection I assume that “big” load balancers handle this seemlessly, i.e. they simply re-route incoming traffic to other processes or machines, or don’t they?
haproxy doesn’t seem to support OS X, which I require (don’t want to have to set up yet another Linux server right now).
Apart from that, I have my solution working nicely now, with the following behaviors and features:
Client can query the server for a license file by sending it a serial code and hardware identification (such as its primary network MAC address).
Server delivers the license for the serial (and generates it if necessary). The license is a signed AquaticPrime file.
Client checks if the license matches the hardware identification it’s running on - if not, it’ll tell the user that the serial is already in use with another computer.
All traffic is encrypted (I’m doing about the same as SSL does, but I roll it myself as I have to perform sync and async encryption/decryption already anyway for the license file).
The server logs all requests, allowing me to detect abuses.
Next, I’ll integrate this with Paypal checkout (and Paypal IPN), so that I can have full integration, where a user can make a purchase for N licenses, the server creates serials for each, and then the user can register N computers, using one serial each. Kind of like what the Xojo IDE does, too.
Not that it sounds like you need it necessarily, but I run those 4 apps I mentioned on a Mac Mini with OS X and haproxy. I installed it with homebrew and it works fine. I’ve been using it for years. I also launch it at startup with a launch daemon like Frederick described.
So just to make sure that if anyone does find this thread that they know they can run haproxy on Mac OS X.
Kevin, I get the impression that haproxy loads each client once and then spawns new processes for each new connection via pfork or something like that. My app is currently a GUI app (so that it can show me its current state and recent events and issues easily in its window) - that would probably not work with haproxy - but I assume you’re using Xojo-built console apps with it? I.e., console apps made with Xojo are compatible with haproxy, right?
I also deal in apps that run for months at a time, or that are only restarted to install updates or when the users power goes out. The main app does a lot of socket communication between its various helper apps and external devices. So far I have not noticed any memory leaks or other issues with the original API sockets, Im not sure yet about the new framework ones as I havent used those except a few xojo.net.httpsockets in any large projects yet.
Since they fixed the 8k limit on individual reads in the serverSocket I am very happy with regular TCP sockets in Xojo. You should have no trouble in your app because of any problem with them or the associated framework parts.
There may be some gotchas elsewhere still But just sockets work great for apps that stay up for months or even a year or longer and constantly transfer data.
You should look into starting it through the launchd system, thats the easiest way to keep things running if the app were to actually crash. Modern OSX Versions will even restart automatically after a kernel panic. Dont ask how I made that happen, its probably not applicable to this discussion When you get a kernel panic dialog now it will actually time out in 30 seconds or so and the machine restart.
The restart after power failure option in the energy saver prefs is a must of course, but there is a very serious bug in 10.11 with this if a UPS is connected via USB! If you have a UPS connected it will NOT restart the machine when the power comes back on. Without a UPS connected it works fine. This could be limited to some kinds of APC UPS units, I havent tested it widely, but it definitely happens on my machine and the machines of several users. I have not tested this on newer OSX versions yet but youll definitely want to test it on your machine if youre going to be hosting it yourself or putting it on a UPS. If youre co-locating somewhere with larger backup power then its not a problem.