How to spin up a rocket server along with other stuff? - rust-rocket

Basically I want to have a single process handling multiple things at the same time (specifically want to have an http endpoint for monitoring a non-http service), but it seems I'm being caught up in Rocket depending on a rocket-specific tokio runtime and I'm not seeing how to get around this. I've thought about having rocket be the main entry point instead of tokio's standard one and launching other stuff from that runtime, but this seems wrong in general and fragile as I might switch libraries. I've thought about using hyper and warp and I'm somewhat confident I could make them work in this situation but want to use rocket as I'm using it elsewhere in this project. I'm using the 0.5-rc01 version.
From the docs:
Rocket v0.5 uses the tokio runtime. The runtime is started for you if you use #[launch] or #[rocket::main], but you can still launch() a Rocket instance on a custom-built runtime by not using either attribute.
Unfortunately I cannot find any further explanation of what requirements this custom-built runtime has nor any examples not using the launch/main macros.
Here's a simplified version of the code I'm trying to use:
#[rocket::get("/ex")]
async fn test() -> &'static str {
"OK"
}
#[tokio::main]
async fn main() {
tokio::spawn(async {
let config = Config {
port: 8001,
address: std::net::Ipv4Addr::new(127, 0, 0, 1).into(),
..Config::debug_default()
};
rocket::custom(&config)
.mount("/", rocket::routes![test])
.launch()
.await;
});
let start = Instant::now();
let mut interval = interval_at(start, tokio::time::Duration::from_secs(5));
loop {
interval.tick().await;
println!("Other scheduled work");
}
}
When I press CTRL-C to terminate the process, the following is printed:
^CWarning: Received SIGINT. Requesting shutdown.
Received shutdown request. Waiting for pending I/O...
Warning: Server failed to shutdown cooperatively.
>> Server is executing inside of a custom runtime.
>> Rocket's runtime is `#[rocket::main]` or `#[launch]`.
>> Refusing to terminate runaway custom runtime.
Other scheduled work
Other scheduled work
Other scheduled work
I've found this documentation explaining that you need to 'cooperate' in shutdown if you're using a custom runtime but it does not explain what cooperation entails. Also, running things besides rocket in the spawned thread causes CTRL-C to kill the process as I would have normally expected, so I think this is related to rocket specifically. What do I need to do so that I can actually kill the process?
Edit: I gave up and switched to warp, which was a thousand times easier. I would still be curious to know the proper way to do this with rocket and would try again if anybody has suggestions.

If we add a config for shutdown to the Rocket.toml, the thread also terminates.
[default.shutdown]
ctrlc = false
signals = ["term", "hup"]
See the documentation for Rocket Shutdown here:
https://api.rocket.rs/v0.5-rc/rocket/config/struct.Shutdown.html#example

I think you could just let Rocket take care of starting your tokio runtime:
#[rocket::main]
async fn main() {
tokio::spawn(async {
let start = Instant::now();
let mut interval = interval_at(start, tokio::time::Duration::from_secs(5));
loop {
interval.tick().await;
println!("Other scheduled work");
}
});
let config = Config {
port: 8001,
address: std::net::Ipv4Addr::new(127, 0, 0, 1).into(),
..Config::debug_default()
};
rocket::custom(&config)
.mount("/", rocket::routes![test])
.launch()
.await;
}
Your own extra logic can be done in the task you spawn and rocket gets launched the normal way.

Related

Launch one Coroutine at a time - Kotlin

We have a button in the UI, which, when pressed, will make some remote network call in its own coroutine. However, if the user spams the button for whatever reason, it is possible that the remote data might somehow get corrupted. We would like to prevent this by discarding all requests until the current one is completed.
There are many ways to do this. I have create a simple extension function on CoroutineScope to only launch if the CoroutineScope is not active. This is what I have created:
Extension Function
fun CoroutineScope.safeLaunch(dispatcher: CoroutineDispatcher, block: () -> Unit): Job {
return if (!isActive) {
launch(dispatcher) {
block()
}
} else {
launch {}
}
}
Example Use
fun loadNotifications() {
viewModelScope.safeLaunch(IO) {
getNotifications.invoke() // Suspend function invoke should only be from a coroutine or another suspend function
}
}
The problem is, the above won't compile as I get an error saying
Suspend function invoke should only be from a coroutine or another
suspend function
Does anyone know what I'm doing wrong or how to make it work?
There are multiple problems with this code:
Fixing the error you mentioned is very easy and requires to only specify block as suspendable: block: suspend () -> Unit.
isActive doesn't mean the job/scope is actively running something, but that it hasn't finished. isActive in your example always returns true, even before launching any coroutine on it.
If your server can't handle concurrent actions, then you should really fix this on server side. Limiting the client isn't a proper fix as it can be still exploited by users. Also, you need to remember that multiple clients can perform the same action at the same time.
As you mentioned, there are several ways how this situation can be handled on the client side:
In the case of UI and the button, it is probably the best for the user experience to disable the button or overlay the screen/button with a loading indicator. It gives the user the feedback that the operation is running in the background and at the same time it fixes the problem with multiple calls to the server.
In general case, if we just need to limit concurrency and reject any additional tasks while the last one is still running, probably the easiest is to use Mutex:
private val scope = CoroutineScope(EmptyCoroutineContext)
private val mutex = Mutex()
fun safeLaunch(block: suspend () -> Unit) {
if (!mutex.tryLock()) {
return
}
scope.launch {
try {
block()
} finally {
mutex.unlock()
}
}
}
Note we need a separate mutex per scope or per the type of the task. I don't think it is possible to create such utility as a generic extension function, working with any coroutine scope. Actually, we can implement it in a very similar way to your original code, but by looking at the current job's children. Still, I consider such solution hacking and I discourage it.

ktor server - when to move to another coroutine context

This may be a question about coroutines in general, but in my ktor server (netty engine, default configuration) application I perform serveral asyncronous calls to a database and api endpoint and want to make sure I am using coroutines efficiently. My question are as follows:
Is there a tool or method to work out if my code is using coroutines effectively, or do I just need to use curl to spam my endpoint and measure the performance of moving processes to another context e.g. compute?
I don't want to start moving tasks/jobs to another context 'just in case' but should I treat the default coroutine context in my Route.route() similar to the Android main thread and perform the minimum amount of work on it?
Here is an rough example of the code that I'm using:
fun Route.route() {
get("/") {
call.respondText(getRemoteText())
}
}
suspend fun getRemoteText() : String? {
return suspendCoroutine { cont ->
val document = 3rdPartyLibrary.get()
if (success) {
cont.resume(data)
} else {
cont.resume(null)
}
}
}
You could use something like Apache Jmeter, but writing a script and spamming your server with curl seems also a good option to me
Coroutines are pretty efficient when it comes to context/thread switching, and with Dispatchers.Default and Dispatchers.IO you'll get a thread-pool. There are a couple of documentations around this, but I think you can definitely leverage these Dispatchers for heavy operations
There are few tools for testing endpoints. Jmeter is good, there are also command line tools like wrk, wrk2 and siege.
Of course context switching costs. The coroutine in routing is safe to run blocking operations unless you have the option shareWorkGroup set. However, usually it's good to use a separate thread pool because you can control it's size (max threads number) to not get you database down.

[kotlin]Mark function as suspendable

I got following functions for making server calls
suspend fun <T: BaseResponse> processPost(post:Post):T? {
val gson=Gson()
val data=gson.toJson(post.reqData)
val res= sendPost(data,post.script)
Log.d("server","res:"+res.first)
//process response here
return null
}
private fun sendPost(data:String,url:String):Pair<String,Int> {
//send data to server
}
In some cases processPost may enter into infinite loop(for instance to wait for access token refresh).Of course this code should never be run on the main thread.But when I mark this function as suspend IDE is highliting it as redundant.Its not big deal but I'm curious how then can I restrict function execution on the main thread?
It seems that you have quite some learning on coroutines to do. It’s impossible to cover all you need to know in one single answer. That’s what tutorials are for. Anyway I will try to answer just the points you asked. It may not make sense before you learn the concepts, I’m sorry if my answer does not help.
Just like many other things, coroutines are not magic. If you don’t understand what something does, you cannot hope it has the properties you want. It may sound harsh but I want to stress that such mentality is a major cause of bugs.
Making a function suspending allows you to call other suspending functions in the function body. It does not make blocking calls non-blocking, nor does it automatically jump threads for you.
You can use withContext to have the execution jump to another thread.
suspend fun xyz() = withContext(Dispatchers.IO) {
...
}
When you call xyz in the main thread, it’ll hand the task to the IO dispatcher. Without being blocked, it can then handle other stuff in the app.
EDIT regarding the comment.
Sorry for being so patronizing and making a wrong guess about your misconception.
If you just want the compiler/the IDE to shut up about the warning, you can simply add #Suppress("RedundantSuspendModifier") to the function. But you shouldn't, because the compiler knows better than you, at least for now.
The great thing about coroutines is that you can write in direct style without blocking the main thread.
launch(Dispatchers.Main) {
val result = makeAnHttpCall() // this can take a long time
messWithUi(result) // changes to the UI has to be in the main thread
}
I hope it is obvious by now that the suspend modifier is not going to stop the main thread from calling the function.
#Suppress("RedundantSuspendModifier")
suspend fun someHeavyComputation(): Result {
return ...
}
launch(Dispatchers.Main) {
val result = someHeavyComputation() // this will run in the main thread
messWithUi(result)
}
Now if you want the computation not to be done in the main thread:
suspend fun someHeavyComputation() = withContext(Dispatchers.Default) {
... // this will be in a thread pool
}
Further reading: Blocking threads, suspending coroutines.

Guaranteed way to cancel a hanging Task?

I often have to execute code on a separate thread that is long running, blocking, instable and\or has a potential to hang forever. Since the existence of TPL the internet is full of examples that nicely cancel a task with the cancellation token but I never found an example that kills a task that hangs. Code that hangs forever is likely to be expected as soon as you communicate with hardware or call some third party code. A task that hangs cannot check the cancellation token and is doomed to stay alive forever. In critical applications I equip those tasks with alive signals that are sent on regular time intervals. As soon as a hanging task is detected, it is killed and a new instance is started.
The code below shows an example task that calls a long running placeholder method SomeThirdPartyLongOperation() which has the potential to hang forever. The StopTask() first checks if the task is still running an tries to cancel it with the cancellation token. If that doesn’t work, the task hangs and the underlying thread is interrupted\aborted old school style.
private Task _task;
private Thread _thread;
private CancellationTokenSource _cancellationTokenSource;
public void StartTask()
{
_cancellationTokenSource = new CancellationTokenSource();
_task = Task.Factory.StartNew(() => DoWork(_cancellationTokenSource.Token), _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
public void StopTask()
{
if (_task.Status == TaskStatus.RanToCompletion)
return;
_cancellationTokenSource.Cancel();
try
{
_task.Wait(2000); // Wait for task to end and prevent hanging by timeout.
}
catch (AggregateException aggEx)
{
List<Exception> exceptions = aggEx.InnerExceptions.Where(e => !(e is TaskCanceledException)).ToList(); // Ignore TaskCanceledException
foreach (Exception ex in exceptions)
{
// Process exception thrown by task
}
}
if (!_task.IsCompleted) // Task hangs and didn't respond to cancellation token => old school thread abort
{
_thread.Interrupt();
if (!_thread.Join(2000))
{
_thread.Abort();
}
}
_cancellationTokenSource.Dispose();
if (_task.IsCompleted)
{
_task.Dispose();
}
}
private void DoWork(CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(Thread.CurrentThread.Name)) // Set thread name for debugging
Thread.CurrentThread.Name = "DemoThread";
_thread = Thread.CurrentThread; // Save for interrupting/aborting if thread hangs
for (int i = 0; i < 10; i++)
{
cancellationToken.ThrowIfCancellationRequested();
SomeThirdPartyLongOperation(i);
}
}
Although I’ve been using this construct for some years now, I want to know if there are some potential mistakes in it. I’ve never seen an example of a task that saves the underlying thread or gives it a name to simplify debugging, so I’m a bit unsure if this is the right way to go. Comment on any detail is welcome!
Code that hangs forever is likely to be expected as soon as you communicate with hardware or call some third party code.
Communication: absolutely not. There's always a way to timeout with communication APIs, so even with misbehaving hardware, there's no need to force-kill an I/O operation.
Third-party code: only if you're paranoid (or have high demands such as 24x7 automation).
Here's the bottom line:
There's no way to force-kill a task.
You can force-kill a thread, but this can easily cause serious problems with application state, possibility if introducing deadlocks in other parts of the code, and resource leaks.
You can force-kill an appdomain, which solves a large portion of app state / deadlock issues with killing threads. However, it doesn't solve them all, and there's still the problem of resource leaks.
You can force-kill a process. This is the only truly clean and reliable solution.
So, if you choose to trust the third-party code, I recommend that you just call it like any other API. If you require 100% reliability regardless of third-party libraries, you'll need to wrap the third-party dll into a separate process and use cross-process communication to call it.
Your current code force-kills a thread pool thread, which is certainly not recommended; those threads belong to the thread pool, not to you, and this is still true even if you specify LongRunning. If you go the kill-thread route (which is not fully reliable), then I recommend using an explicit thread.
The question is why is this task even hanging at all? I think there's no universal solution to this problem but you should focus on the task to be always responsible and not on forcing to interrupt it.
In this code, it looks like you're looking for a simple thread rather than a task - you shouldn't link tasks to threads - it's very likely that the task will switch to another thread after some async operations and you will end up on killing an innoccent thread that is not connected to your task anymore. If you really need to kill the whole thread then make a dedicated one just for this job.
You shouldn't also name or do anything with any thread that is used for tasks' default pool. Consider this code:
static void Main(string[] args)
{
Task.Run(sth);
Console.Read();
}
static async Task sth()
{
Thread.CurrentThread.Name = "My name";
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(Thread.CurrentThread.Name ?? "No name");
}
the output is:
3
4
No name

Synchronous XMLHttpRequest deprecated

Today, I had to restart my browser due to some issue with an extension. What I found when I restarted it, was that my browser (Chromium) automatically updated to a new version that doesn't allow synchronous AJAX-requests anymore. Quote:
Synchronous XMLHttpRequest on the main thread is deprecated because of
its detrimental effects to the end user's experience. For more help,
check http://xhr.spec.whatwg.org/.
I need synchronous AJAX-requests for my node.js applications to work though, as they store and load data from disk through a server utilizing fopen. I found this to be a very simplistic and effective way of doing things, very handy in the creation of little hobby projects and editors... Is there a way to re-enable synchronous XMLHttpRequests in Chrome/Chromium?
This answer has been edited.
Short answer:
They don't want sync on the main thread.
The solution is simple for new browsers that support threads/web workers:
var foo = new Worker("scriptWithSyncRequests.js")
Neither DOM nor global vairables aren't going to be visible within a worker but encapsulation of multiple synchronous requests is going to be really easy.
Alternative solution is to switch to async but to use browser localStorage along with JSON.stringify as a medium. You might be able to mock localStorage if you allowed to do some IO.
http://caniuse.com/#search=localstorage
Just for fun, there are alternative hacks if we want to restrict our self using only sync:
It is tempting to use setTimeout because one might think it is a good way to encapsulate synchronous requests together. Sadly, there is a gotcha. Async in javascript doesn't mean it gets to run in its own thread. Async is likely postponing the call, waiting for others to finish. Lucky for us there is light at the end of the tunnel because it is likely you can use xhttp.timeout along with xhttp.ontimeout to recover. See Timeout XMLHttpRequest
This means we can implement tiny version of a schedular that handles failed request and allocates time to try again or report error.
// The basic idea.
function runSchedular(s)
{
setTimeout(function() {
if (s.ptr < callQueue.length) {
// Handles rescheduling if needed by pushing the que.
// Remember to set time for xhttp.timeout.
// Use xhttp.ontimeout to set default return value for failure.
// The pushed function might do something like: (in pesudo)
// if !d1
// d1 = get(http...?query);
// if !d2
// d2 = get(http...?query);
// if (!d1) {pushQue tryAgainLater}
// if (!d2) {pushQue tryAgainLater}
// if (d1 && d2) {pushQue handleData}
s = s.callQueue[s.ptr++](s);
} else {
// Clear the que when there is nothing more to do.
s.ptr = 0;
s.callQueue = [];
// You could implement an idle counter and increase this value to free
// CPU time.
s.t = 200;
}
runSchedular(s);
}, s.t);
}
Doesn't "deprecated" mean that it's available, but won't be forever. (I read elsewhere that it won't be going away for a number of years.) If so, and this is for hobby projects, then perhaps you could use async: false for now as a quick way to get the job done?

Resources