Vapor 3 Timers?

My main remote database is iCloud. It provides everything I need except iCloud doesn’t have any “smarts” built into it. One of the things I need to do is check for “expired” items every 5 minutes or so and then update the public database. I tried to have my iOS app have the “smarts” but things get pretty dicey when there are 100’s of users running “expire”. So my thinking the way to do this is have a Vapor server have a “shadow” database of my public items, run the expire on those items, and use server-to-server operations to remove the “real” items from iCloud.

The question is how do I run a periodic function in Vapor? I noticed one of your postings on stack overflow said to use NIO. Can you elaborate a little bit with an example? I’m a real novice when it comes to backend programming.

Thanks.

@gilroykilroy the ‘best’ way of doing this is still undecided. Honestly NSTimer works well for individual tasks. Take a look at the Jobs package. It depends on the work you are doing - you may want to do lots of work, or spawn different pieces of work at which point you may need to use NIOs threads to do the job

Didn’t I read the Jobs package wasn’t really good under 3.0?

It depends on the work, for things like fire and forget requests it works well. For things that needs to do some actual work you can starve the CPU. There’s a large discussion on the Swift NIO GitHub here

0xtim My timer is to update the database. How should I so this in a thread-safe fashion since I read Fluent isn’t thread-safe since you “normally” pass in a request container and I guess I would be using the app container.

One cheesy way is my timer could send myself a http request…

I just saw this How to use the timer in vapor 3 ? 🦄 · Issue #1696 · vapor/vapor · GitHub. I assume that would work?

@gilroykilroy you can use the app as your worker, as long as you use the same worker throughout your work, you don’t have to worry about thread safety (since it’s the same thread).

Another option to the one you posted is https://github.com/apple/swift-nio/pull/488 when that gets implemented

So then the app needs to be the worker for db actions in route handling as well and not the request? The docs have this warning:

“Do not use database connections created by the application in a route closure (when responding to a request). Always use the incoming request to create a connection to avoid threading issues.”

@0xtim Can you please help with this when you get a chance? Thank you - much appreciated! :]

@gilroykilroy an application is already a worker, so you can use other. It depends where you’re using it. If you want to connect to the database in a request handler, use the request. If you want to do it outside of requests (such as in a timer) use the app. They both have their own thread pools, the app gets one and the requests get the number of threads of the CPU (IIRC)

I understand. I just want to be sure there would be no database thread safe issues with both the timer (using the app worker) and the request (using the request worker) both accessing and changing the same database.

@gilroykilroy databases are designed to handle multiple concurrent connections, accesses, reads and writes - it’s their job! It allows you to scale one database powering multiple server instances etc