How to catch parse errors in Lucerne (common lisp) - json

I'm trying to build a simple rest api in Lucerne, but the clack:call method fails if the json is malformed. So, I extended the bass-app class and added an around method:
(defclass tracker-app (base-app) ()
(:documentation "An extension of lucerne's base app to control behavior"))
(defmethod clack:call :around ((app tracker-app) env)
(handler-case (call-next-method)
(fast-http:cb-message-complete (e)
(vom:error "could not build message body: ~a" e)
(respond nil :status 400))
(:no-error (res) res)))
(defapp server :class 'tracker-app)
(start server :server woo)
But the parse error continues to crash the server.
I don't know much about clos, so I'm worried I've misunderstood how to catch errors in this context.
Edit: Added start information
Edit: Added stack trace

Assuming *features* does not contain :catch-any-error, here is a complete test case:
(ql:quickload :lucerne)
(defpackage :so.lucerne (:use :cl :lucerne))
(in-package :so.lucerne)
(defclass tracker-app (base-app) ()
(:documentation "An extension of lucerne's base app to control behavior"))
(defmethod clack:call :around ((app tracker-app) env)
(handler-case (call-next-method)
(fast-http:cb-message-complete (e)
(warn "could not build message body: ~a" e)
(respond nil :status 400))
#+catch-any-error
(error (e) (break "BREAK with ~a" e))
(:no-error (res) res)))
(defmethod clack:call ((app tracker-app) env)
(error "Oh No"))
(defapp server :class 'tracker-app)
(start server :server :woo)
When I try to load localhost:8000, the following error is shown:
Callback Error: the message-complete callback failed
Oh No
[Condition of type FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE]
Pressing Enter on [Condition of type FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE] gives:
#<FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE {10048315C3}>
--------------------
The object is a CONDITION of type FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE.
FORMAT-CONTROL: NIL
FORMAT-ARGUMENTS: NIL
DESCRIPTION: "the message-complete callback failed"
ERROR: #<SIMPLE-ERROR "Oh No" {1004831583}>
The error wraps another error.
Now if I (push :catch-any-error *features*) and recompile the above method, the same test makes the code reach the (break ...) statement, which is shown as BREAK with Oh No.
Explanation
No fast-http:cb-message-complete is caught, and in fact no such condition is signaled at this point; instead at this location we only can catch the specific error that was signaled. It is only higher up in the call stack that errors are wrapped inside fast-http:cb-message-complete errors.
Solution
In your case you can directly catch jonathan.error:<jonathan-error> (unusual naming convention, but ok), the base class of all errors in the jonathan library (you could catch the specific error type, but then you risk missing some other cases).

[This answer is wrong: fast-http.error:cb-message-complete & fast-http:cb-message-complete seem to be the same symbol. I am leaving it here for posterity.]
You are not handling the right condition (and in fact I'm not sure you're handling a condition which exists at all, which I'd expect the system to have warned about perhaps, although perhaps it can't).
You need to handle fast-http.error:cb-message-complete, but your handler specifies fast-http:cb-message-complete. The first of these is a condition (defined here, while the second is I think implicitly define here and is not a condition but the name of a function I think.
A more general trick is to try to handle some much-too-general error: you will probably end up handling things you don't know how to handle, but if your handler gets invoked you know that the call stack looks like you think it does when the error is signalled. Then you can start handling the errors you actually care about. In this case that probably means fast-http.error:callback-error I think.

Related

Handling exceptions in Spring 5 Reactive kotlin

I've been hitting the wall and haven't came up with any reasonable solution, so maybe someone will give it a try. I wrote simple service integrating with github, and having hard time to understand how should I work with exceptions in reactive word properly. Once I got expected 404 status error from Github I would like to throw my custom exception and present it to the client instead of valid response, I'm checking code statuses of response from github and the only thing I receive on my site is:
2018-06-26 21:45:08.286 WARN 8336 --- [ctor-http-nio-2]
.a.w.r.e.DefaultErrorWebExceptionHandler : Failed to handle request
[GET http://localhost:8080/repositories/sh1nen/no-exist]: Response
status 404
Here is my simple method responsible for making requests and handling error codes appropriately.
fun findSpecificOwnerRepository(owner: String, repositoryName: String) = webClient
.get()
.uri("/repos/$owner/$repositoryName")
.retrieve()
.onStatus({ httpStatus -> HttpStatus.NOT_FOUND == httpStatus }, { Mono.error(RepositoryNotFoundException(reason = "Repository $repositoryName not found.")) })
.onStatus({ httpStatus -> HttpStatus.SERVICE_UNAVAILABLE == httpStatus }, { Mono.error(RepositoryNotFoundException(reason = "Service unavailable.")) })
.bodyToMono(GithubRepositoryResponse::class.java)
Here is my custom exception which basically represents no resources on my site to represent:
internal class RepositoryNotFoundException(
status: HttpStatus = HttpStatus.NOT_FOUND,
reason: String? = null,
throwable: Throwable? = null) : ResponseStatusException(status, reason, throwable)
And the endpoint itself which I'm hitting to get the response:
#GetMapping("{owner}/{repositoryName}")
fun findSpecificOwnerRepository(#PathVariable owner: String, #PathVariable repositoryName: String) = githubClient
.findSpecificOwnerRepository(owner, repositoryName)
I would like to get 404 with a message which is hardcoded. Do I need any special #ExceptionHandler in controller to handle my custom exception ?
Is there any chance of implementing situation when for example github is not able to keep up with requests I am serving and throw in that case also some exception? How could it be implemented?
I'm not sure if you are actually missing anything for point 1), as the exception you extend should naturally result in 404 to your clients, if I recall correctly.
About point 2, it all depends on how your source handles rate limiting. In the case of GitHub, it will return a 403 once you hit rate limits, but you can be extra careful and check the custom headers as well. See https://developer.github.com/v3/#rate-limiting
So the simplest way it would be implemented is with onStatus. Alternatively, you can inspect the whole response and act accordingly by using exchange instead of retrieve, and flatMaping on the resulting Mono (that emits the whole server response).

How to avoid affecting other code when panic error or something else in golang

I am writing a monitor program that will merge into company's system. When the program running, seldom panicked some error since a variety of problem such as a few other's server doesn't obtain the rule of http, network error or anything else.I fix most of them but I am still afraid of influence on the master program by possibly potential errors.
From company's aspect, the stability of master program is most important, secondly, monitoring's result, the stability of monitoring is low-priority.
Is there have a method can isolate error? For example,"try...except Exception..." in python to ignore error(Admittedly, Not recommended)How to avoid effect other code when panic error or something else in golang
With panics, you can use recover like this
func recoverExample() {
defer func() {
if panicMessage := recover(); panicMessage != nil {
fmt.Printf("Panic '%v' captured", panicMessage)
}
}()
panic("Oh no!")
}
With output:
Panic 'Oh no!' captured
User recover function at the top of your function in which you have the chances of getting error. Don't use panic as it will stop the execution of your code. Use below code snippet. Also It will print the log which will let you know in which function the exception occurred.
defer func() {
if r := recover(); r != nil {
log.Println("Recovered in custom function", r)
}
}()

Apache Camel:RabbitMQ Requeing a message to the same queue causes duplication of message

I'm doing something like
from(rabbitmq:pollingQueue?prefetchSize=1&concurrentConsumer=10)
.process(pollingRequestStatus) // check status of the request, if not ready, requeue = true
.Choice
.when(requeue == true) // request not ready
.to(rabbitmq:pollingQueue)//back to the same queue
.endChoice
.otherwise
.to(proceedToSomethingElse)
.endChoice.end;
When the requeue happens, the message gets duplicated, is this an expected behavior when sending back the message to the same queue?
I have also tried something like the following as suggested but it does not work,the message seems to be just consumed and won't requeue
from(rabbitmq:pollingQueue? prefetchSize=1&concurrentConsumer=10)
.onException(NotReadyException.class)
.handled(true)
.setHeader(RabbitMQConstants.REQUEUE, constant(true))
.end()
.process(pollingRequestStatus) // check status of the request, if not ready, throw NotReadyEception
.to(proceedToSomethingElse);
The other two ways i have tried that at least does not create duplicates,
1.) on NotReadyExeption, send the message back to the pollingQueue
from(rabbitmq:pollingQueue? prefetchSize=1&concurrentConsumer=10)
.onException(NotReadyException.class)
.to(rabbitmq:pollingQueue)
//.delay(constant(8000)) //not sure why it throws error if i set delay
.end
.process(pollingRequestStatus); // check status of the request, if not ready, throw NotReadyEception
This works, however, it runs too quick, like instantly.
If i set delay(constant(number)), the following error is thrown,
Exception in thread "main" org.apache.camel.FailedToCreateRouteException: Failed to create route route13 at: >>> From [bla bla bla...]
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1062)
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:196)
at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:984)
at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:3401)
at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:3132)
at org.apache.camel.impl.DefaultCamelContext.access$000(DefaultCamelContext.java:183)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:2961)
at org.apache.camel.impl.DefaultCamelContext$2.call(DefaultCamelContext.java:2957)
at org.apache.camel.impl.DefaultCamelContext.doWithDefinedClassLoader(DefaultCamelContext.java:2980)
at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:2957)
at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)
at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:2924)
at com.mbww.ithink.runner.Main.main(Main.java:174)
Caused by: java.lang.IllegalArgumentException: Route route13 has no output processors. You need to add outputs to the route such as to("log:foo").
at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:1060)
2.) On NotReadyException, redeliver based on redeliveryPolicy
from(rabbitmq:pollingQueue? prefetchSize=1&concurrentConsumer=10)
.onException(NotReadyException.class)
.setFaultBody(constant(false))
.maximumRedeliveries(-1) // -1 = redeliver forever
.redeliveryDelay(10000)
.end
.process(pollingRequestStatus); // check status of the request, if not ready, throw NotReadyEception
Originally the idea of requeue is so that if the request is not ready, requeue the message to be back of the queue, set a delay and check the status of the next request, and avoid getting things like Ratelimit error.
seems like the redelivery policy is the way to go now.
Thanks
To be able to requeue the message you have to turn off RabbitMQ's auto-acknowledgement. In that case you have to manually send the ack, nack or reject message back to the publisher. (https://www.rabbitmq.com/confirms.html)
It means you have to manually call one of the basicAck, basicNack or basicReject function on the current Channel implementation.
Translated to Camel:
To turn of auto-acknowledgement add the autoAck=false to the endpoint parameters.
AFAIK, the Camel Endpoint's underlying Channel is not accessible (source) so you can't directly call the Channel's basicReject(long deliveryTag, boolean requeue) function, but Camel does call it when the exchange is failed (exception occured during to routing).
The workaround might be the following: (pseudocodish and I haven't tried it, but based on checking the camel-rabbitmq endpoint's source, especially this part)
Updated workaround (tested and working):
from("rabbitmq://localhost:5672/first?queue=test&concurrentConsumers=10prefetchSize=1&autoAck=false&autoDelete=false")
.onException(NotReadyException.class)
.log("Error for ${body}! Requeue")
.asyncDelayedRedelivery().redeliveryDelay(5000) // wait 5 secs to redeliver and requeue
.maximumRedeliveries(1)
.setHeader(RabbitMQConstants.REQUEUE, constant(true))
.handled(true)
.setFaultBody(constant(true))
.end()
.log("Received: ${body}")
.process((e) -> {
if(notReady(e))
throw new NotReadyException(); // create a new Exception and throw it if the status is not ready
}
})
.to("direct:somethingElse");
Also I created a gist which implements almost a same scenario.
Hope it helps!
You don't need to send the message again, just set rabbitmq.REQUEUE property to true. If this property is set, rabbitmq component will automatically requeue the message instead of discarding it. From the docs:
Camel 2.14.2: This is used by the consumer to control rejection of the
message. When the consumer is complete processing the exchange, and if
the exchange failed, then the consumer is going to reject the message
from the RabbitMQ broker. The value of this header controls this
behavior. If the value is false (by default) then the message is
discarded/dead-lettered. If the value is true, then the message is
re-queued.
So, inside your processor you can do something like:
exchange.getIn().setHeader("rabbitmq.REQUEUE", true);
And then just check REQUEUE header == false in your route to call proceedToSomethingElse.

How to return values in Invoke json response

I am trying to design a hyperledger chaincode, that is accessed through a web API, which passes json objects to the code. However, whenever I do an invoke method, I cannot actually return values to the user in the json response.
For instance, here is some sample code:
func (t *TLCChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
//Do some stuff
return []byte("Some string"), nil
}
And some sample code for returning an error
func (t *TLCChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
//Try to do some stuff
//Get some sort of error
return nil, errors.New("someError")
}
however both of these return a message like this, with the message always being some random character string like below (I suspect a hash of some sort):
{
"jsonrpc": "2.0",
"result": {
"status": "OK",
"message": "1e1123e3-b484-4120-a28e-c3a8db384557"
},
"id": 11
}
As you can see, this response contains neither the response I returned (as in the first case), or the error I returned (in the second case). How would I go about getting the returned bytes, or the returned error into the returned json?
Edit: Please note that if I call an invoke method from another chaincode, it receives the correct return values. It's only when it's returned to the user that it fails to work properly.
“Invoke” is not a synchronous call. Peer generates this OK message immediately when it receives your Web request.
Later, when Validation peers will try to generate new block, this “invoke” method will be executed together with other cached transactions.
In its turn chaincode-to-chaincode calls are synchronous and executed simultaneously.
As a workaround we use another Query request to check the status of this submitted Invoke. It would be great if anybody can propose better solution.
If you need to get a return value as soon as the Invoke is processed (included in a block), your best bet is to use some events (for the moment I guess).
In your chaincode, just setup the event with:
func (stub *ChaincodeStub) SetEvent(name string, payload []byte) error
GoDoc
You may be able to listen for events in your application using the SDK or protobuf messages directly. I'm doing it like this on the developer preview; but it seems that the standard way to retrieve Invoke result is to poll the blockchain via Queries.
There is a related GitHub issue here.

Uncaught SyntaxError: Unexpected token B on live but not local server

So i am making some ajax post and it seems to work fine on the localhost, but when I publish it to ec2 server on amazon, I get Uncaught SyntaxError: Unexpected token B. Which seems to point to JSON parsing failure. Exact same database, same browser, and same methods being called. Why would it work on local and not on the server.
$.ajax({
url: '#Url.Action("Action")',
type: "POST",
data: ko.toJSON(viewModel),
dataType: "json",
contentType: "application/json; charset:utf-8",
success: function (result) {
},
error: function (xhr, textStatus, errorThrown) {
var errorData = $.parseJSON(xhr.responseText);
var errorMessages = [];
for (var key in errorData)
{
errorMessages.push(errorData[key]);
}
toastr.error(errorMessages.join("<br />"), 'Uh oh');
}
});
Here is the basic layout on the server side:
[HttpPost]
public JsonResult Action(ViewModel model)
{
try
{
Response.StatusCode = (int)HttpStatusCode.OK;
return Json("Successfull");
}
catch (Exception ex)
{
logger.Log(LogLevel.Error, string.Format("{0} \n {1}", ex.Message, ex.StackTrace));
Response.StatusCode = (int)HttpStatusCode.BadRequest;
List<string> errors = new List<string>();
errors.Add(ex.Message);
return Json(errors);
}
}
Within the try statement, I do a couple of queries to the database and post some calculations on Authorize.Net (https://api.authorize.net/soap/v1/Service.asmx)
If there are any error with Authorize.net web service calls then I return errors like this:
if (profile.resultCode == MessageTypeEnum.Error)
{
logger.Log(LogLevel.Error, string.Join(",", profile.messages.Select(x => x.text)));
Response.StatusCode = (int)HttpStatusCode.BadRequest;
List<string> errors = new List<string>();
profile.messages.ToList().ForEach(x => errors.Add(x.text));
db.SaveChanges();
return Json(errors);
}
This error that I am logging:
A public action method 'AddPromoCode' was not found on controller 'Flazingo.Controllers.PositionController'. at
System.Web.Mvc.Controller.HandleUnknownAction(String actionName) at
System.Web.Mvc.Controller.ExecuteCore() at
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) at
System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<>c__DisplayClassb.b__5() at
System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.b__0() at
System.Web.Mvc.MvcHandler.<>c__DisplayClasse.b__d() at
System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean&
completedSynchronously)
You have another post at can't find action only on live server, works fine in local server, so I'm guessing that this post is specifically related to the javascript pieces, not the server-side pieces.
It sounds like something bad happens on the server, the server sends back some type of error, and the your error handler (in javascript) dies when trying to handle that response.
I get Uncaught SyntaxError: Unexpected token B. Which seems to point
to JSON parsing failure.
That sounds quite reasonable. Let's look at the code:
.ajax({
...
error: function (xhr, textStatus, errorThrown) {
var errorData = $.parseJSON(xhr.responseText);
var errorMessages = [];
...
},
...
});
I would highly recommend taking a look at what xhr.responseText is. My guess it that it does not contain valid JSON, so the parseJSON method throws the 'Unexpected token B' error.
To look at this value, you could put console.log(xhr.responseText); or you could use a tool like the javascript debugger in your web browser or fiddler to see what is there.
My guess is that the server is sending back a string with something like There was an error on the server instead of JSON like you are expecting. I see that you have error handling built in - my guess is that there is an error within your error handling, and there is nothing to catch it. I would recommend doing debugging on the server side to see if there is an error somewhere that you are not expecting.
Perhaps profile.messages is something that can only be enumerated once, and when you try to do it again it throws an error. Or maybe DB.SaveChanges is throwing an error for some reason. Either of these would result in the logged message that you see with the behavior you see on the client side.
You are attempting to return a 400 response (Bad Request) with your own custom response content.
I think that IIS by default doesn't allow you to do this, and as CodeThug mentioned, may be replacing your custom JSON content with a server message.
But it appears that you can override this behaviour:
http://develoq.net/2011/returning-a-body-content-with-400-http-status-code/
<system.webServer>
<httpErrors existingResponse="PassThrough"></httpErrors>
</system.webServer>
I have received similar mysterious errors in the past when using ASP.NET script bundling on knockout and bootstrap, especially when including the already-minified versions in a bundle.
If you are running in DEBUG mode on localhost, then ASP.NET will not be minifying the javascript libraries. However, once you deploy, you are presumably no longer in DEBUG mode and now minifying/bundling the scripts. Sometimes the bundling/minification of these scripts can result in syntax errors similar to the one you posted.
If so, you may be able to load knockout from a CDN to avoid the need for bundling.
It seems JSON sending as the response from the server is badly generated
ex: if a value in the database is hi "my" friends
JSON file will be generated as text:"hi "my" friends"
so value for property text is badly generated.
double check values in production/development server for such values.
best practice is replace quotes with escape character
ex: text:"hi \"my\" friends"