I have written a simple command line tool in dart that watches changes in a directory if a directory does not exits I get FileSystemsException.
I have tried to handle it using try and catch clause. When the exception occurs the code in catch clause is not executed
try {
watcher.events.listen((event) {
if (event.type == ChangeType.ADD) {
print("THE FILE WAS ADDED");
print(event.path);
} else if (event.type == ChangeType.MODIFY) {
print("THE FILE WAS MODIFIED");
print(event.path);
} else {
print("THE FILE WAS REMOVED");
print(event.path);
}
});
} on FileSystemException {
print("Exception Occurs");
}
I expect the console to print "Exception Occurs"
There are two possibilities:
The exception is happening outside this block (maybe where the watcher is constructed?)
The exception is an unhandled async exception. This might be coming from either the Stream or it might be getting fired from some other Future, like perhaps the ready Future.
You can add handlers for the async exceptions like this:
try {
// If this is in an `async` method, use `await` within the try block
await watcher.ready;
// Otherwise add a error handler on the Future
watcher.ready.catchError((e) {
print('Exception in the ready Future');
});
watcher.events.listen((event) {
...
}, onError: (e) {
print('Exception in the Stream');
});
} on FileSystemException {
print("Exception Occurs");
}
My guess would be it's an error surfaced through the ready Future.
Related
In Electron if I throw an error anywhere on the backend it goes to a custom window. Trying to find a way to catch that to push to a custom area in my app I've found that I can detect the process with process.on('uncaughtException'). However I'm stuck trying to run a sender to send either the error or the report. What I've tried:
ipcMain.on('main', async (e, data) => {
try {
await someModule(data)
process.on('uncaughtException', err => e.sender.send('error', err.message))
return e.sender.send('audit', 'No issues found')
} catch (err) {
console.log(err)
}
})
module.js:
module.export = data => {
throw Error('this is a test')
}
In the above I'm sending both get both errorandaudit` to renderer. I've researched for a way to pass 'uncaughtException' to a ternary but I'm not able to find any docs on how to condition for 'uncaughtException' but I did try:
process.on('uncaughtException', err => {
if (err) return e.sender.send('error', err.message)
return e.sender.send('audit', 'test complete')
})
and the above only works if an error is present, research:
Catch all uncaughtException for Node js app
Nodejs uncaught exception handling
Node.js Uncaught Exception - Passing more details
In Electron how can I intercept the error to pass it to renderer from main without throwing the default error window?
If you use ipcMain.handle you will be able to handle errors in the renderer process like this
// Main process
ipcMain.handle('my-invokable-ipc', async (event, data) => {
await someModule(data)
return 'No issues found'
})
// Renderer process
async () => {
try {
const result = await ipcRenderer.invoke('my-invokable-ipc', data)
console.log(result) // 'No issues found' if someModule did not throw an error
} catch (err) {
// you can handle someModule errors here
}
}
Update: An issue with this approach is that the error emitted to the renderer process is serialized and it gets printed even though it's handled with a try/catch.
To fix this, you can also handle the errors in the main process
// Main process
ipcMain.handle('my-invokable-ipc', async (event, data) => {
try {
await someModule(data)
return 'No issues found'
} catch (err) {
// handle someModule errors and notify renderer process
// return err.message or any other way you see fit
}
})
// Renderer process
async () => {
const result = await ipcRenderer.invoke('my-invokable-ipc', data)
console.log(result) // 'No issues found' if someModule did not throw an error
}
This is my code of sync event. Am I doing wrong by handling the promise of sync() method? Should not I handle promise which is inside event.waitUntil() method?
`self.addEventListener('sync', function(event) {
if (event.tag == "esssync") {
event.waitUntil(sync()
.then(function(data){
console.log(data);
try{
if (Notification.permission === 'granted'){
self.registration.showNotification("Sync success" + data);
}else{
console.log("Sync success");
}
}catch(err){
console.log("Sync success");
}
})
.catch(function(err){
console.log("Could not sync, scheduled for the next time");
}));
}
});`
Jake Archibald's guide to Background Sync is a great source of information; it contains the following:
[The promise passed to event.waitUntil indicates]
the success/failure of whatever it’s trying to do. If it
fulfills, the sync is complete. If it fails, another sync will be
scheduled to retry.
You're passing in a promise that always fulfills, because you have a .catch() function at the end of it, and you don't throw an error or return a rejected promise from within that .catch(). You just have a single console.log() statement.
The .catch() function is analogous to the catch block in traditional try {} / catch {} exception handling. You need to re-throw the original error from inside your catch {} block if you want it to propagate up the call stack, and the same thing applies with .catch() if you want the error to cause the promise to reject.
event.waitUntil(
sync()
.then(data => /* do something with data */)
.catch(error => {
console.log('Could not sync; scheduled for the next time', error);
throw error; // Alternatively, `return Promise.reject(error);`
}))
);
You can also just leave out the .catch() entirely, and rely on the fact that passing in the rejected promise to event.waitUntil() should log something in the JavaScript console by default.
I'm building an app with Silex and Twig where I have my route handlers defined in this way (standard way):
//routes.php
$app->get('/pageA',function () use($app){
//Display something
});
$app->get('/pageB',function () use($app){
//Display something
});
$app->post('/pageB',function (Request $req) use($app){
//Process something
});
And then I have set up an error handler to manager possible errors that are thrown inside the route handlers, like this:
//routes.php
$app->post('/pageB',function (Request $req) use($app){
//Do something, but an error occurs..
$app->abort(404,"Page not found");
});
//errors.php
$app->error(function (\Exception $e, $code) use($app) {
switch($code){
case 404:
return $app['twig']->render('404.twig',array('error'=>$e->getMessage()));
//Other error codes...
default:
//return something
}
});
What I would like to do is pass an extra parameter from the route handler to the callback function of the error handler, like this:
//routes.php
$app->post('/pageB',function (Request $req) use($app){
//Do something, but an error occurs..
$app->abort(404,"Page not found","My extra parameter");
});
//errors.php
$app->error(function (\Exception $e, $code,$extra_param=null) use($app) {
if(isset($extra_param))
//Process the error in a different way
else{ //Standard way
switch($code){
case 404:
return $app['twig']->render('404.twig',array('error'=>$e->getMessage()));
//Other error codes...
default:
//return something
}
}
});
Can this be done?
This might not be the most elegant solution but you could probably just add an array to $app.
$app['my_param_bag'] = array();
$app->get('/pageB', function(Request $request) use ($app) {
$app['my_param_bag'] = array('foo', 'bar', 'baz');
$app->abort(404, "Page not found");
});
$app->error(function (\Exception $e, $code) use($app) {
error_log(print_r($app['my_param_bag'],1).' '.__FILE__.' '.__LINE__,0);
if(!empty($app['my_param_bag'])) {
// do something with the params
}
else{
switch($code){
case 404:
return $app['twig']->render('404.html.twig',array('error'=>$e->getMessage()));
default:
}
}
});
I'm not sure about how you have your application setup but for me I was able to add this empty array in a configuration file.
I use my postgres database query to determine my next action. And I need to wait for the results before I can execute the next line of code. Now my conn.query returns a Future but I can't manage to get it async when I place my code in another function.
main() {
// get the database connection string from the settings.ini in the project root folder
db = getdb();
geturl().then((String url) => print(url));
}
Future geturl() {
connect(db).then((conn) {
conn.query("select trim(url) from crawler.crawls where content IS NULL").toList()
.then((result) { return result[0].toString(); })
.catchError((err) => print('Query error: $err'))
.whenComplete(() {
conn.close();
});
});
}
I just want geturl() to wait for the returned value but whatever I do; it fires immediately. Can anyone point me a of a piece of the docs that explains what I am missing here?
You're not actually returning a Future in geturl currently. You have to actually return the Futures that you use:
Future geturl() {
return connect(db).then((conn) {
return conn.query("select trim(url) from crawler.crawls where content IS NULL").toList()
.then((result) { return result[0].toString(); })
.catchError((err) => print('Query error: $err'))
.whenComplete(() {
conn.close();
});
});
}
To elaborate on John's comment, here's how you'd implement this using async/await. (The async/await feature was added in Dart 1.9)
main() async {
try {
var url = await getUrl();
print(url);
} on Exception catch (ex) {
print('Query error: $ex');
}
}
Future getUrl() async {
// get the database connection string from the settings.ini in the project root folder
db = getdb();
var conn = await connect(db);
try {
var sql = "select trim(url) from crawler.crawls where content IS NULL";
var result = await conn.query(sql).toList();
return result[0].toString();
} finally {
conn.close();
}
}
I prefer, in scenarios with multiple-chained futures (hopefully soon a thing of the past once await comes out), to use a Completer. It works like this:
Future geturl() {
final c = new Completer(); // declare a completer.
connect(db).then((conn) {
conn.query("select trim(url) from crawler.crawls where content IS NULL").toList()
.then((result) {
c.complete(result[0].toString()); // use the completer to return the result instead
})
.catchError((err) => print('Query error: $err'))
.whenComplete(() {
conn.close();
});
});
return c.future; // return the future to the completer instead
}
To answer your 'where are the docs' question: https://www.dartlang.org/docs/tutorials/futures/
You said that you were trying to get your geturl() function to 'wait for the returned value'. A function that returns a Future (as in the example in the previous answer) will execute and return immediately, it will not wait. In fact that is precisely what Futures are for, to avoid code doing nothing or 'blocking' while waiting for data to arrive or an external process to finish.
The key thing to understand is that when the interpreter gets to a call to then() or 'catchError()' on a Future, it does not execute the code inside, it puts it aside to be executed later when the future 'completes', and then just keeps right on executing any following code.
In other words, when using Futures in Dart you are setting up chunks of code that will be executed non-linearly.
Following the tutorial on DartWatch blog on using Google OAuth library. The question is how to handle: 'Access denied' error from Google ?
Here is my code example:
class Client
{
GoogleOAuth2 _auth;
Client()
{
_auth = new GoogleOAuth2(
'5xxxxxxxxxxxxxx.apps.googleusercontent.com', // Client ID
['openid', 'email', 'profile'],
tokenLoaded:oauthReady);
}
void doLogin()
{
// _auth.logout();
// _auth.token = null;
try
{
_auth.login();
}
on AuthException {
print('Access denied');
}
on Exception catch(exp)
{
print('Exception $exp occurred');
}
}
void oauthReady(Token token)
{
print('Token is: $token');
}
}
but I never hit catch block on any (!) exception. What I'm doing wrong ?
I'm using:
Dart Editor version 0.5.0_r21823
Dart SDK version 0.5.0.1_r21823
You never hit the catch block because auth.login is an asynchronous operation which returns a Future.
There is a great article on Future error handling on the dartlang.org website.
auth.login returns a Future immediately, but the work it does happens after control returns to the event loop (see my answer to another question for more on the event loop.)
Your code should look more like:
/// Returns a Future that completes to whether the login was successful.
Future<boolean> doLogin()
{
_auth.login()
.then((_) {
print("Success!");
return true;
}.catchError((e) {
print('Exception $e occurred.');
return false; // or throw the exception again.
}
}