How are function failures propagated for NodeJS Wrapped C++ Code? - c++

I am specifically interested in how this nodeJS wrapper for quickfix node-quickfix handles failures on sending FIX messages out. The function signature in question seems to be:
function send([Object], callback fn)
This can be seen in the example given here.
Under the hood, node-quickfix takes advantage of NodeJS nan to bind to C++ code. The underlying quickfix package is C++. What I'm curious about is how an error in this send function, say from a network disconnect, is propagated to JS code. In node-quickfix's FIXSession class it overwrites nan's HandleOKCallback (but not its HandleErrorCallback):
void HandleOKCallback () {
Nan::HandleScope scope;
v8::Local<v8::Function> fn = callback->GetFunction();
if(!(fn->IsUndefined() || fn->IsNull())) {
Local<Value> argv[] = { Nan::Null() };
callback->Call(1, argv);
}
};
The definition of nan's default HandleOKCallback and HandleErrorCallback are here. It seems like the FIXInitiator does have an error callback, but I do not know how it is propagated or accessed in javascript/NodeJS for that matter.
EDIT1: I've added a github issue with what I suspect is the issue but I do not know if it is correct, or what the solution is. There is some additional information with my analysis in the github issue.
EDIT2: Added suggested changes to node-quickfix: FixSendWorker.cpp Execute():
void FixSendWorker::Execute () {
try {
FIX::Session::sendToTarget(*message);
} catch(FIX::SessionNotFound& e) {
this->SetErrorMessage("Failed to send FIX Message");
std::cout << "*** Session not found!" << std::endl;
}
}
Code Snippets I used inside my initiator:
console.log('sleeping for 5 seconds');
sleep(5000)
console.log('done sleeping');
this.send(req, (err) => {
console.log(`ERROR: ${err}`);
});
Definition of sleep:
function sleep(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {
}
}

I checked the nan Execute function in node-quickfix and it is catching a specific exception and not propagating it:
void FixSendWorker::Execute () {
try {
FIX::Session::sendToTarget(*message);
} catch(FIX::SessionNotFound& e) {
std::cout << "*** Session not found!" << std::endl;
}
}
In order to make nan invoke the HandleErrorCallback you should call the SetErrorMessage() function in the catch block of the Execute function. That will cause the error callback on the nodejs side to be called with the error message passed to SetErrorMessage.
I used this post for a source: https://medium.com/#muehler.v/tutorial-to-native-node-js-df4118efb678

Related

Catching/Handling exceptions thrown in AngelScript functions

I'm playing around with AngelScript, and one thing I can't seem to wrap my head around is how to catch exceptions thrown from C++ but called from AngelScript. Here's what I've got so far:
// test.as
void main()
{
print("Calling throwSomething...");
throwSomething();
print("Call finished");
}
void print(string) and void throwSomething() are two functions registered to the engine, source below. As per the AngelScript docs:
Application functions and class methods registered with the script engine are allowed to throw C++ exceptions. The virtual machine will automatically catch any C++ exception, abort the script execution, and return control to the application.
Here's the example code provided for handling exceptions:
asIScriptContext *ctx = engine->CreateContext();
ctx->Prepare(engine->GetModule("test")->GetFunctionByName("func"));
int r = ctx->Execute();
if( r == asEXECUTION_EXCEPTION )
{
string err = ctx->GetExceptionString();
if( err == "Caught an exception from the application" )
{
// An application function threw an exception while being invoked from the script
...
}
}
I pretty much verbatim copied this code into my editor and tried to run it. Unfortunately, even though I wrapped the call to Execute in a try-catch block, I still get this output:
(AngelScript) Calling throwSomething...
(C++) throwSomething Entered...
libc++abi.dylib: terminating with uncaught exception of type std::runtime_error: Assert(1 == 0) failed, line 68
Abort trap: 6
For completeness' sake, here's the code for throwSomething and print:
void throwSomething()
{
cout << "(C++) throwSomething Entered...\n";
Assert(1 == 0); // will throw an exception
cout << "(C++) throwSomething Exiting...\n";
}
void print(string s)
{
cout << "(AngelScript) " << s << "\n";
}
So, I'm feeling a little stuck. I tried registering an exception translation function (see linked doc) in hopes that would help, but I still got the same results. From looking at Xcode's debugger, the exception appears to happen in the main thread-- so I'm unsure why neither my code or the code in the AngelScript library itself catches the exception.
So, I guess my question is: 1) how can I either catch the exception within my program, or 2) If I can't catch it from within the program, how can I otherwise handle it without the program crashing?
I'm running this on a ~2015 MacBook Pro running MacOS 10.14.6 and AngelScript version 2.33.0, if that's relevant.

In UWP application, future.wait() keep waiting while trying to synchronize the response from async methods

I am working on developing an UWP application which would load the file from Application local data on click of a Button. For this, I need the StorageFolder object for Application LocalFolder using StorageFolder::GetFolderFromPathAsync() method then i will have to use GetFileAsync() method to read the StorageFile object to read.
I have written the templates to wait for the response from async methods like GetFolderFromPathAsync(), GetFileAsync(), etc. before proceeding.
template <typename T>
T syncAsyncTask(concurrency::task<T> mainTask) {
std::shared_ptr<std::promise<T>> done = std::make_shared<std::promise<T>>();
auto future = done->get_future();
asyncTaskExceptionHandler<T>(mainTask, [&done](bool didFail, T result) {
done->set_value(didFail ? nullptr : result);
});
future.wait();
return future.get();
}
template <typename T, typename CallbackLambda>
void asyncTaskExceptionHandler(concurrency::task<T> mainTask, CallbackLambda&& onResult) {
auto t1 = mainTask.then([onResult = std::move(onResult)](concurrency::task<T> t) {
bool didFail = true;
T result;
try {
result = t.get();
didFail = false;
}
catch (concurrency::task_canceled&) {
OutputDebugStringA("Win10 call was canceled.");
}
catch (Platform::Exception^ e) {
OutputDebugStringA("Error during a Win10 call:");
}
catch (std::exception&) {
OutputDebugStringA("There was a C++ exception during a Win10 call.");
}
catch (...) {
OutputDebugStringA("There was a generic exception during a Win10 call.");
}
onResult(didFail, result);
});
}
Issue :
When i call syncAsyncTask() method with any task to get
its response, it keeps waiting at future.wait() as mainTask never
complete and promise never set its value.
See below code :
void testStorage::MainPage::Btn_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
Windows::Storage::StorageFolder^ localFolder = Windows::Storage::ApplicationData::Current->LocalFolder;
auto task = concurrency::create_task(Windows::Storage::StorageFolder::GetFolderFromPathAsync(localFolder->Path));
auto folder = syncAsyncTask<Windows::Storage::StorageFolder^>(task);
printString(folder->Path);
}
void printString(Platform::String^ text) {
std::wstring fooW(text->Begin());
std::string fooA(fooW.begin(), fooW.end());
const char* charStr = fooA.c_str();
OutputDebugStringA(charStr);
}
Running environment :
VS2017
Tried with C++14 and C++17, facing same issue.
Windows 10 RS5 Build#17763
Has anyone ever faced this issue?
Please help!! Thanks in advance.
I was able to take the above code and create a simple application that reproduced this issue. Long story short, I was able to get future.wait() to return by telling the continuation in asyncTaskExceptionHandler to run on a background thread:
template <typename T, typename CallbackLambda>
void asyncTaskExceptionHandler(concurrency::task<T> mainTask, CallbackLambda&& onResult) {
// debug
printString(mainTask.is_apartment_aware().ToString());
auto t1 = mainTask.then([onResult = std::move(onResult)](concurrency::task<T> t) {
bool didFail = true;
T result;
try {
result = t.get();
didFail = false;
}
catch (concurrency::task_canceled&) {
OutputDebugStringA("Win10 call was canceled.");
}
catch (Platform::Exception^ e) {
OutputDebugStringA("Error during a Win10 call:");
}
catch (std::exception&) {
OutputDebugStringA("There was a C++ exception during a Win10 call.");
}
catch (...) {
OutputDebugStringA("There was a generic exception during a Win10 call.");
}
// It works with this
}, concurrency::task_continuation_context::use_arbitrary());
}
Assuming the code I used was correct, what I believe to be happening is that we created a deadlock. What we are saying with the above code is:
On the UI/STA thread, create/handle an async operation from GetFolderFromPathAsync
Pass this task off to our syncAsyncTask, which in turn passes this off to asyncTaskExceptionHandler.
asyncTaskExceptionHandler adds a continuation to this task which schedules it to run. By default, tasks run on the thread that called them. In this case, it is the UI/STA thread!
Once the thread is scheduled, we return back to syncAsyncTask to finish. After our call to asyncTaskExceptionHandler we have a future.wait() which blocks until the promise value is set.
This prevents our UI thread from finished execution of the syncAsyncTask, but also prevents our continuation from running since it is scheduled to run on the same thread that is blocking!
In other words, we are waiting on the UI thread for an operation to complete that cannot begin until the UI thread is finished, thus causing our deadlock.
By using concurrency::task_continuation_context::use_arbitrary() we tell the task that it's okay to use a background thread if necessary (which in this case it is) and everything completes as intended.
For documentation on this, as well as some example code illustrating async behavior, see the Creating Asynchronous Operations in C++ for UWP Apps documentation.

C++ read global variable flag in namespace from std::async function

So my use case is the following: I have a handful of functions and fields defined inside a namespace. One of these functions will initialize the fields, then run another function inside a call to std::async. The function called should run indefinitely until flagged to stop, most commonly from outside of its own thread. The basic code looks something like this
namespace Game
{
void Create() {
Initialize();
auto returned = std::async(RunGameLoop, std::ref(FLAGS));
}
}
Now, the way I have attempted to implement this is by initializing these flags in the namespace:
namespace Game
{
namespace // This is used because the fields and functions here should be for internal use only
{
bool stopped = false;
}
}
Inside the RunGameLoop function the basic structure is set up like this
namespace Game
{
namespace // This is used because the fields and functions here should be for internal use only
{
void RunGameLoop()
{
while (!stopped)
{
// ... do stuff
}
}
}
}
But seemingly due to how async works, if I change the value of stopped from anywhere other than inside the RunGameLoop function, the RunGameLoop function does not see any change. Presumably when creating the async function call, C++ simply copies all values in scope at the time of construction, passing them by value instead of reference.
My question is: How do I make this change noticeable inside the async function loop? Or even better: Is there a better way to communicate simple global flags like this with an async function in C++? I have experimented with using std::ref, passing pointers, and passing an entire map of flags by reference, but seemingly no changes made outside of the RunGameLoop function will be noticeable inside the RunGameLoop function.
Edit: I've managed to replicate the issue in a minimal example, this program will run indefinitely, and indeed never reach the second std::cout statement, counterintuitively. The std::async call does, in fact, not seem to run the function asynchronously at all, which is a bit harsher than what I experienced in my own project. I acknowledge I might be misunderstanding how std::async is supposed to be used, but it seems like this code should work to me.
Edit 2: I bungled my prior example, so I fixed it. Unfortunately now it seems to behave as expected, unlike my actual project:
#include <iostream>
#include <future>
namespace test
{
namespace
{
std::atomic<bool> testbool = false;
std::future<void> returned;
void queryTestBool()
{
while (!testbool)
{
}
std::cout << "EXITED THREAD: " << std::boolalpha << testbool << std::endl;
}
}
void Initialize()
{
testbool = false;
}
void Delete()
{
testbool = !testbool;
returned.get();
}
void Create()
{
Initialize();
returned = std::async(queryTestBool);
}
}
int main()
{
using namespace test;
std::cout << std::boolalpha << testbool << std::endl;
Create();
Delete();
std::cout << std::boolalpha << testbool << std::endl;
}
This program outputs
false
EXITED THREAD: true
true
meaning that not only does the Delete function successfully change the value of testbool, but that change is noticed in the asynchronous while loop. This last part is what isn't happening in my own project for some reason, even when I use std::atomic. I will investigate further.
So I feel massively stupid. After struggling with this for weeks, implementing all sorts of stuff, I finally discovered that the place my test called the Delete() function was being skipped because of a failed assertion that I didn't expect to make the test exit before running the rest... Mystery solved

Qooxdoo: How to call MMock.verify() in an asynchronous test

I'm trying to use qx.dev.unit.MMock.verify() in an asynchronous situation effectively the same as this:
, test_no_output_from_verify: function () {
var mocker = this.mock({ callMeOnce: function () { } });
mocker.expects('callMeOnce').once();
qx.event.Timer.once(function () {
mocker.verify();
this.resume();
}, this, 100);
this.wait(1000);
}
I find that, when the verify() call throws an exception (because the callMeOnce function was not called), that exception is swallowed by the Test Runner. It carries on waiting for the 1000ms timeout to elapse, and then throws the standard timeout exception: 'Asynchronous Test Error: Timeout reached before resume() was called.'.
Is there any way that I can make Test Runner halt immediately and display the exception thrown from mocker.verify() instead?
==============================
EDIT: Reading the manual one more time after posting the question shows my mistake. The correct technique is to put the verify() call inside the resume(), thus:
, test_no_output_from_verify: function () {
var mocker = this.mock({ callMeOnce: function () { } });
mocker.expects('callMeOnce').once();
qx.event.Timer.once(function () {
this.resume(function () {
mocker.verify();
});
}, this, 100);
this.wait(1000);
}
This works as expected and I get the ExpectationError: Expected callMeOnce([...]) once (never called) message inside the Test Runner.

How to reschedule a concurrent task?

Short explanation in bold.
I have a tbb::task that can be summed up like that:
class UpdateTask
: public tbb::task
{
public:
tbb::task* execute()
{
// some work...
if( can_continue() )
{
// make sure this is re-executed
this->recycle_to_reexecute(); //looks like it is deprecated but it's more clear to me
return nullptr; // ? or this? or tbb::empty_task?
}
return nullptr;
}
};
I want this task to be rescheduled as soon as its finished until a condition is filled.
I'm allocating this task this way:
UpdateTask& updater = *new(tbb::task::allocate_root()) UpdateTask();
Not sure it's related to the problem though.
The problem: When I run the code, I get assertions (in Debug) from tbb (last revision, 4.1.5) and I can't find a way to make it work correctly.
I've re-read the documentation but I can't find a simple example of this and it is not clear to me what I'm doing wrong.
I made some experiments:
With the code I just show, the assertion says that I should return a task:
Assertion t_next failed on line 485 of file ...\itbb\src\tbb\custom_scheduler.h
Detailed description: reexecution requires that method execute() return another
task
Then if I return this, the assertions says that the task should be allocated:
Assertion t_next->state()==task::allocated failed on line 452 of file ...\itbb\src\tbb\custom_scheduler.h
Detailed description: if task::execute() returns task, it must be marked as allo
cated
In doubt I tried to return a tbb::empty_task that I create on the fly (to check), allocated as new(tbb::task::allocate_child()) tbb::empty_task(). I got assertion with this message Assertion p.ref_count==0 failed on line 107 of file ...\itbb\src\tbb\custom_scheduler.h
Detailed description: completion of task caused predecessor's reference count to
underflow.
So, how to do it? I assume it is simple but can't find the way it is done.
Is it related to task reference counting?
Update: here is a full code that is a good aproximation of what I have:
#include <iostream>
#include <atomic>
#include <tbb/tbb.h>
namespace test { class UpdateTask : public tbb::task { public:
UpdateTask() { std::cout << "[UpdateTask]" << std::endl; }
~UpdateTask() { std::cout << "\n[/UpdateTask]" << std::endl; }
tbb::task* execute() { std::cout << "Tick "<< m_count <<std::endl;
++m_count;
// make sure this is re-executed this->recycle_to_reexecute(); //return new(tbb::task::allocate_continuation()) tbb::empty_task(); return nullptr; }
private:
std::atomic<int> m_count;
};
tbb::task_list m_task_list;
void register_update_task() { UpdateTask& updater =
*new(tbb::task::allocate_root()) UpdateTask(); m_task_list.push_back( updater ); }
void run_and_wait() { tbb::task::spawn_root_and_wait( m_task_list ); }
void tbb_test() { register_update_task(); run_and_wait();
}
}
int main()
{
test::tbb_test();
std::cout << "\nEND";
std::cin.ignore();
return 0;
}
So, here I got the first exception saying that I should return a task. In execute() function, if I replace the return by the one commented, then it appear to work, but there are two problems with this:
I have to create an empty_task task EVERY TIME a call to execute is done???
After the first call to execute(), the main thread is resumed. This is NOT what spawn_root_and_wait() is supposed to do. After all the task is not finished and is correctly rescheduled.
I must conclude it's not the right way to do this either.
this->recycle_to_reexecute();
is deprecated.
Replace by:
this->increment_ref_count();
this->recycle_as_safe_continuation();
Enjoy
P.S.: end of course(in yours case) return NULL from execute.