I have this code, hoping to catch all exception during this async method. Somehow, an url exception happened but it was not caught by the catch clause. I have to add a try-catch block around it to catch that exception, don't know why, can someone explain?
public async transform(
): Promise {
const {result} = this.processUrl(url).catch(error => error);
return result;
}
private processUrl(url: string): Promise {
const targetHostname = new URL(url).hostname; // exception thrown here invalid url something
// do something else ...
return Promise.resolve(targetHostname);
}
I was hoping tranform function will never throw exception, but when I provide an invalid url, processUrl method throws out an exception which somehow didn't get caught in the transform function.
I have to do this to catch it.
public async transform(
): Promise {
try {
const {result} = this.processUrl(url).catch(error => error);
} catch(e) {
// invalid url exception got caught
return Promise.resolve(undefined);
}
return result;
}
processURL() is not an async function. Thus, it does not automatically return a promise and does not automatically catch exceptions and turn them into a rejected promise.
So, if an exception is thrown anywhere in processURL(), that exception just propagates upwards as a synchronous exception. If you want to catch that synchronous exception yourself, you will need a try/catch in order to catch it.
Or, you could make processURL() an async function and then it will automatically catch any synchronous exceptions and turned them into a rejected promise that you could then catch with .catch() like this:
private async processUrl(url: string): Promise {
const targetHostname = new URL(url).hostname; // exception thrown here invalid url something
// do something else ...
return Promise.resolve(targetHostname);
}
Or you could catch it manually:
private processUrl(url: string): Promise {
try {
const targetHostname = new URL(url).hostname; // exception thrown here invalid url something
// do something else ...
return Promise.resolve(targetHostname);
} catch(e) {
return Promise.reject(e);
}
}
You may also have an issue here:
const {result} = this.processUrl(url).catch(error => error);
Because your processUrl() function is set up to return a promise. You need to use .then() or await to get the value out of that promise. FYI, if processUrl() is actually entirely synchronous, then it is just complicating matters to make it return a promise when it could just return a value directly.
Related
i'm using recoil selectorFamily witch subscribes several selector or selectorFamily for data query.
and also using the try...catch for tracking each data query's status.
and then i figured out that CATCH state catch the promise object on default excution.
so it makes the function calling dataQuery consider it exception but there is no exception.
i wonder why this happend.
and also how can i sure if promiseState loged on browser is fulfilled or pending?
i'm confusing cause it's marked <pending> but it's promiseState property saying 'fulfilled'.
here is code and browser log as result
const dataQueryForPage = selectorFamily<{data:IPageData; message:string|null;status:number},number>({
key:'dataQueryForPage',
get:(refreshKey)=> async({get})=>{
try{
const data1 = await get(data1Query);
const data2 = await get(data2Query);
const data3 = await get(data3Query);
...
}catch(error){
console.log('---------------------------------error', error);
if (error instanceof Promise) {
error
.then(() => {
console.log('--------------------------------its resolved');
})
.catch(() => {
console.log('-------------------------------its rejected');
});
...
}
})
Why are Promises caught?
The get function provided by the parameters of selector callback throws them.
If get receives a pending atom, it throws a Promise to interrupt the evaluation. The evaluation will be restarted when the thrown Promise is resolved.
Source code:
https://github.com/facebookexperimental/Recoil/blob/main/packages/recoil/recoil_values/Recoil_selector.js#L724
And get does NOT return a Promise but the awaited value. So it's not necessary to put an await before get(data1Query)
Inconsistent PromiseState
The console evaluates lazily.
In your case, each state was evaluated twice. The first time was the Promise being logged to console. The second time was you expanded the properties.
The displayed value corresponded to the state at that very moment.
So I have this function which sends request to the API and I want to throw exception when requests fails:
async function getCampaigns() {
try {
const response = await api.get('/cars');
setSelectItems(
response.map((item: Car) => ({
label: item.carLabel,
value: item.carValue
}))
);
setLoading(false);
} catch (error: any) {
const exception = new Exception(error);
exception.kind = 'recoverable';
throw exception;
}
}
I created custom exception to handle errors in this code:
Exception.ts
type ExceptionType = 'nonrecoverable' | 'recoverable';
export class Exception extends Error {
public kind: ExceptionType;
constructor(message?: string, options?: ErrorOptions) {
super(message, options);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, Exception);
}
this.kind = 'nonrecoverable';
this.name = 'Exception';
}
}
However I am getting the following error whenever I get error response:
Unhandled Runtime Error
Exception: AxiosError: Request failed with status code 401
which is pointing at this line:
const exception = new Exception(error);
Not sure why is this happening and how can I throw the custom error like this?
EDIT:
So the actual problem here is that, when I catch the error and throw custom one based on the error caught I throw it again in the catch block. I think this results in the custom error that is being thrown uncaught.
And because the custom error is uncaught, in Next.js development mode I get this error Overlay telling me about unhandled error...
Even though I have ErrorBoundary component that works as inteded (so redirects to the error component) but still Next.js overlay is displayed. So I am not sure how should I handle the custom error inside catch block in this situation? Is this correct approach already and should I leave it as it is or is there some better wayt to do this?
How do I store something from a conn.execute complete block?
https://docs.snowflake.com/en/user-guide/nodejs-driver-use.html#executing-statements
Basically I want to do something like this:
async function checkRecords(conn: Connection, sqlText: string): Promise<number> {
return new Promise ((resolve, reject) => {
try {
conn.execute({
sqlText: sqlText,
complete: function(err, stmt, rows) {
if (err) {
reject(err);
} else {
let ret = parseInt(rows[0].COUNT);
return Promise.resolve(ret);
}
}
});
} catch (err) {
error(err);
}
});
}
I think my question is similar to How can I execute Snowflake statement in async mode using NodeJs Snowflake driver? but I did not find any answer there.
Because of the async nature of the complete I never manage to return the value of the complete block.
I've tried to make it await, I've tried to make the function async and return a promise the point is that when I then call the function it still always ignores the wait (and I see in the log the executions with the actual result after my code that was supposed to wait for it already moved one).
Honestly I did not find any good example of this based in Snowflake SDK so I was wondering if anyone knows of a good example to test thigs.
I've seen a lot of different posts on javascript about this like
How to return the response from an asynchronous call
But honestly I do not get it so I really wanted to know if someone has some example based on the Snowflake SDK I could use for inspiration.
I will close this question but somehow I can't make my code wait on the promise
Basically this code just does nothing.
checkRecords(conn, stmtTextStage).then(value => {
if (value > 0) {
log(`STAGE.${name} contains ${value} unique records!`);
} else {
log(`STAGE.${name} contains no records!`, 'WARN');
}
});
well I did manage to make it work but took me a while because I really don't understand this Promise resolve thing but something like this did work:
async function checkRecords(conn: Connection, sqlText: string): Promise<number> {
return new Promise ((resolve, reject) => {
try {
conn.execute({
sqlText: sqlText,
complete: function(err:SnowflakeError, stmt: Statement, rows: any[]) {
if (err) {
error(`${stmt.getSqlText()} : ${err.code}`);
reject(0);
} else {
if (rows.length === 1) {
resolve(parseInt(rows[0].COUNT));
} else {
error(`${sqlText} returned un-expeted rows!`);
reject(0);
}
}
}
});
} catch (err) {
error(err);
}
});
}
Trying to make this work:
try{
message.author.send(helpEmbed)
}
catch(error) {
message.channel.send("Your dms are closed, cannot send help message.")
return;
}
message.react('✅')
But catch(error) doesn't work for a promise error (as the actual error log calls it UnhandledPromiseRejectionWarning). And I can't use .catch(() => etc because then I can't put a return inside of it, meaning it won't stop the message.react. And in a try/catch you can't leave the catch() empty.
I want to add some request timings to the response headers of a request to a Nancy module. I've added some before/after request handlers into the RequestStartup and added the headers no problem (example below) and all was good. I've also added an OnError handler to the ApplicationStartup, to catch errors and return a nice formatted Json response.
pipelines.BeforeRequest += ctx =>
{
ctx.Items.Add("X-RequestStart", DateTime.Now.ToString());
return null;
};
pipelines.AfterRequest += ctx =>
{
var now = DateTime.Now;
try
{
//Not got around to forcing the culture on the datetime parsing yet...
var startTime = DateTime.Parse(ctx.Items["X-RequestStart"].ToString());
ctx.Response.Headers.Add("X-RequestStart", startTime.ToString(CultureInfo.InvariantCulture));
ctx.Response.Headers.Add("X-RequestComplete", now.ToString(CultureInfo.InvariantCulture));
ctx.Response.Headers.Add("X-RequestDuration", (now - startTime).ToString());
}
catch (Exception)
{
ctx.Response.Headers.Add("X-RequestComplete", now.ToString(CultureInfo.InvariantCulture));
}
};
pipelines.OnError += (ctx, exception) =>
{
return ErrorResponse.FromException(exception);
};
What I am noticing however, is that when I have an error thrown, the AfterRequest action is not performed - thus I have no timing headers in to the error response. I've tried moving the before/after request handling to the application startup, but this has no effect either.
The question is in two parts really, firstly, is it possible to get the framework to perform an AfterRequest action after the OnError action has been performed, or is the pipeline set up in a way to prevent this, and secondly, should these before/after request actions be part of the RequestStartup or ApplicationStartup? ApplicationStartup seemed sensible for error handling, whereas RequestStartup seemed sensible for interacting with the response headers as it should be on a per request basis, but I'm not sure if there is a convention for this, or if my assumptions were incorrect.
Unfortunately, this does not seem possible in NancyFx. I took a detailed look at the source code, specifically DefaultRequestDispatcher. Dispatch catches any exceptions thrown during route processing, calls ResolveErrorResult, then gets the response from the negotiator. There does not appear to be an extensibility point to modify responses generated in this way.
In my opinion, this is an oversight that the developers should consider addressing.
public async Task<Response> Dispatch(NancyContext context, CancellationToken cancellationToken)
{
// TODO - May need to make this run off context rather than response .. seems a bit icky currently
var resolveResult = this.Resolve(context);
context.Parameters = resolveResult.Parameters;
context.ResolvedRoute = resolveResult.Route;
try
{
context.Response = await ExecuteRoutePreReq(context, cancellationToken, resolveResult.Before)
.ConfigureAwait(false);
if(context.Response == null)
{
context.Response = await this.routeInvoker.Invoke(resolveResult.Route, cancellationToken,
resolveResult.Parameters, context)
.ConfigureAwait(false);
if (context.Request.Method.Equals("HEAD", StringComparison.OrdinalIgnoreCase))
{
context.Response = new HeadResponse(context.Response);
}
}
await this.ExecutePost(context, cancellationToken, resolveResult.After, resolveResult.OnError)
.ConfigureAwait(false);
}
catch(Exception ex)
{
context.Response = this.ResolveErrorResult(context, resolveResult.OnError, ex);
if (context.Response == null)
{
throw;
}
}
return context.Response;
}
private Response ResolveErrorResult(NancyContext context, Func<NancyContext, Exception, dynamic> resolveResultOnError, Exception exception)
{
if (resolveResultOnError != null)
{
var flattenedException = exception.FlattenInnerExceptions();
var result = resolveResultOnError.Invoke(context, flattenedException);
if (result != null)
{
return this.negotiator.NegotiateResponse(result, context);
}
}
return null;
}