Handle JDBC exception in BIRT API - scheduled-tasks

I have a scheduler job which is based on a standalone RunAndRenderTask. The report design connects to a remote mysql database to fetch data. The scheduler generates a PDF and emails the report as attachment to a set of people. This works as long as the database is available.
But when the database is unavailable, then I can see the error in the logs, but the RunAndRenderTask still generates a PDF report which is blank and useless, and this gets emailed by the scheduler. I need to be able to catch this exception and instead email another set of people who can fix the DB issue. I tried various things but couldn't figure out how to do it.
In the code below, I expect the API to return an exception, and hence print "BirtException" or "Exception", but this code prints "Success" even when there is a JDBC exception.
Any help is appreciated.
Here's the code I have.
IReportEngine engine = null;
IRunAndRenderTask runAndRenderTask = null;
try {
EngineConfig config = new EngineConfig();
config.setEngineHome("birt-runtime-4_4_0/RuntimeEngine");
Platform.startup(config);
IReportEngineFactory factory = (IReportEngineFactory) Platform
.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
engine = factory.createReportEngine(config);
IReportRunnable reportRunnable = engine.openReportDesign(DATA_PATH + "sample.rptdesign");
runAndRenderTask = engine.createRunAndRenderTask(reportRunnable);
PDFRenderOption option = new PDFRenderOption();
option.setOutputFileName(DATA_PATH + "output.pdf");
option.setOutputFormat("pdf");
runAndRenderTask.setRenderOption(option);
runAndRenderTask.run();
System.out.println("Success!");
} catch (BirtException e) {
System.out.println("BirtException");
e.printStackTrace();
} catch (Throwable e) {
System.out.println("Exception");
e.printStackTrace();
} finally {
if (runAndRenderTask != null) {
runAndRenderTask.close();
}
if (engine != null) {
engine.destroy();
}
Platform.shutdown();
RegistryProviderFactory.releaseDefault();
}
This is the exception stacktrace, which never gets propagated back by RunAndRenderTask.run()
INFO: Loaded JDBC driver class in class path: com.mysql.jdbc.Driver
Jun 26, 2014 9:26:43 PM org.eclipse.birt.data.engine.odaconsumer.ConnectionManager openConnection
SEVERE: Unable to open connection.
org.eclipse.birt.report.data.oda.jdbc.JDBCException: There is an error in get connection, Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server..
at org.eclipse.birt.report.data.oda.jdbc.JDBCDriverManager.doConnect(JDBCDriverManager.java:336)
at org.eclipse.birt.report.data.oda.jdbc.JDBCDriverManager.getConnection(JDBCDriverManager.java:235)
at org.eclipse.birt.report.data.oda.jdbc.Connection.connectByUrl(Connection.java:252)
at org.eclipse.birt.report.data.oda.jdbc.Connection.open(Connection.java:162)
at org.eclipse.datatools.connectivity.oda.consumer.helper.OdaConnection.open(OdaConnection.java:250)
at org.eclipse.birt.data.engine.odaconsumer.ConnectionManager.openConnection(ConnectionManager.java:165)
at org.eclipse.birt.data.engine.executor.DataSource.newConnection(DataSource.java:224)
at org.eclipse.birt.data.engine.executor.DataSource.open(DataSource.java:212)
at org.eclipse.birt.data.engine.impl.DataSourceRuntime.openOdiDataSource(DataSourceRuntime.java:217)
at org.eclipse.birt.data.engine.impl.QueryExecutor.openDataSource(QueryExecutor.java:435)
at org.eclipse.birt.data.engine.impl.QueryExecutor.prepareExecution(QueryExecutor.java:322)
at org.eclipse.birt.data.engine.impl.PreparedQuery.doPrepare(PreparedQuery.java:463)
at org.eclipse.birt.data.engine.impl.PreparedDataSourceQuery.produceQueryResults(PreparedDataSourceQuery.java:190)
at org.eclipse.birt.data.engine.impl.PreparedDataSourceQuery.execute(PreparedDataSourceQuery.java:178)
at org.eclipse.birt.data.engine.impl.PreparedOdaDSQuery.execute(PreparedOdaDSQuery.java:178)
at org.eclipse.birt.report.data.adapter.impl.DataRequestSessionImpl.execute(DataRequestSessionImpl.java:637)
at org.eclipse.birt.report.engine.data.dte.DteDataEngine.doExecuteQuery(DteDataEngine.java:152)
at org.eclipse.birt.report.engine.data.dte.AbstractDataEngine.execute(AbstractDataEngine.java:275)
at org.eclipse.birt.report.engine.executor.ExtendedGenerateExecutor.executeQueries(ExtendedGenerateExecutor.java:205)
at org.eclipse.birt.report.engine.executor.ExtendedGenerateExecutor.execute(ExtendedGenerateExecutor.java:65)
at org.eclipse.birt.report.engine.executor.ExtendedItemExecutor.execute(ExtendedItemExecutor.java:62)
at org.eclipse.birt.report.engine.internal.executor.dup.SuppressDuplicateItemExecutor.execute(SuppressDuplicateItemExecutor.java:43)
at org.eclipse.birt.report.engine.internal.executor.wrap.WrappedReportItemExecutor.execute(WrappedReportItemExecutor.java:46)
at org.eclipse.birt.report.engine.internal.executor.l18n.LocalizedReportItemExecutor.execute(LocalizedReportItemExecutor.java:34)
at org.eclipse.birt.report.engine.layout.html.HTMLBlockStackingLM.layoutNodes(HTMLBlockStackingLM.java:65)
at org.eclipse.birt.report.engine.layout.html.HTMLPageLM.layout(HTMLPageLM.java:92)
at org.eclipse.birt.report.engine.layout.html.HTMLReportLayoutEngine.layout(HTMLReportLayoutEngine.java:100)
at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.doRun(RunAndRenderTask.java:181)
at org.eclipse.birt.report.engine.api.impl.RunAndRenderTask.run(RunAndRenderTask.java:77)
at test.ReportTester.test(ReportTester.java:50)
at test.ReportTester.main(ReportTester.java:19)

In addition to catching BirtException, you should be aware that the way BIRT handles Javascript errors is - by default - browser-like. That is, BIRT tries to continue generating the report.
There are different ways to handle this for production-quality code (where task is a RunAndRenderTask or RunTask or RenderTask):
Use task.setErrorHandlingOption(CANCEL_ON_ERROR) (see BIRT docs). Personally, I have never tried this.
After task.run(...), but before task.close(), call task.getErrors(). If this list is not empty, your code should output these messages and throw an exception.

You need to add catch block that catches EngineException, not JDBC exception.
You can find javadocs at link.

Related

Why can not I read bytes from the TcpClient in C#?

Why can not I read bytes from the TcpClient in C#?
Here is the error I am getting:
Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
Here is how I start my TcpClient:
public static async void Start()
{
TcpListener server = null;
try
{
server = new TcpListener(IPAddress.Loopback, 13000);
server.Start();
var client = await server.AcceptTcpClientAsync();
var stream = client.GetStream();
var bytes = Convert.FromBase64String("ABCD");
await stream.WriteAsync(bytes, 0, bytes.Length);
client.Close();
}
catch (Exception e)
{
throw;
}
finally
{
if(server != null)
{
server.Stop();
}
}
}
Here is how I run a request to the TcpClient:
try {
var response = (new HttpClient()).GetByteArrayAsync("http://localhost:13000").Result;
return Convert.ToBase64String(response);
} catch(Exception e) {
throw;
}
The return Convert.ToBase64String(response); line is never reached. While I see the quoted above error message inside the Exception e if I hit a breakpoint on the throw line.
Also, during debug the Start() method completes just fine. I.e. it starts, then wait for a request, gets a request, writes to the TclClient and at the end runs the server.Stop(); command.
I am expecting my code to work, because I took it and modified from the official documentation over here.
I tried to check out a few resources which would tackle my exception, but none of them did help.
E.g. I tried to use the question.
First answer tells nothing useful actually, but just plays around with words and at the end states that one can do nothing about the exception (please, correct me if I am missing a point in the answer).
And the second answer tells an impossible in my case problem. Because, I am sure there is nothing running on the 13000 port.
Your client code is using HttpClient, which sends an HTTP request and expects an HTTP response. But your server is not an HTTP server, it is just a plain TCP server, so the client is likely to fail and forcibly close the connection when it doesn't receive a properly formatted HTTP response.
The "official documentation" whose example you modified is not using HttpClient at all, it is using TcpClient instead.
If you want to use HttpClient in your client, then you should use HttpListener instead of TcpListener in your server.

SignalR Core - Error: Websocket closed with status code: 1006

I use SignalR in an Angular app. When I destroy component in Angular I also want to stop connection to the hub. I use the command:
this.hubConnection.stop();
But I get an error in Chrome console:
Websocket closed with status code: 1006
In Edge: ERROR Error: Uncaught (in promise): Error: Invocation canceled due to connection being closed. Error: Invocation canceled due to connection being closed.
It actually works and connection has been stopped, but I would like to know why I get the error.
This is how I start the hub:
this.hubConnection = new HubConnectionBuilder()
.withUrl("/matchHub")
.build();
this.hubConnection.on("MatchUpdate", (match: Match) => {
// some magic
})
this.hubConnection
.start()
.then(() => {
this.hubConnection.invoke("SendUpdates");
});
EDIT
I finally find the issue. Its caused by change streams from Mongo. If I remove the code from SendUpdates() method then OnDisconnected is triggered.
public class MatchHub : Hub
{
private readonly IMatchManager matchManager;
public MatchHub(IMatchManager matchManager)
{
this.matchManager = matchManager;
}
public async Task SendUpdates() {
using (var changeStream = matchManager.GetChangeStream()) {
while (changeStream.MoveNext()) {
var changeStreamDocument = changeStream.Current.FullDocument;
if (changeStreamDocument == null) {
changeStreamDocument = BsonSerializer.Deserialize<Match>(changeStream.Current.DocumentKey);
}
await Clients.Caller.SendAsync("MatchUpdate", changeStreamDocument);
}
}
}
public override async Task OnDisconnectedAsync(Exception exception)
{
await base.OnDisconnectedAsync(exception);
}
}
Method GetChangeStream from the manager.
ChangeStreamOptions options = new ChangeStreamOptions() { FullDocument = ChangeStreamFullDocumentOption.UpdateLookup };
var watch = mongoDb.Matches.Watch(options).ToEnumerable().GetEnumerator();
return watch;
But I don't know how to fix it.
This can be for many reasons but i think it is most likely this one:
I think this is because of how the server is handling the connected / disconnected events. I can't say for sure but the connection closing needs to handled correctly on the server also with code. Try overriding the built in On Connected /Disconnected methods on the server and see. My assumption only is that you're closing it but the server isn't closing properly and therefore not relaying the proper closed response.
found as a comment at : getting the reason why websockets closed with close code 1006
Where you don't need to change the connection/disconection because evrything works fine. But as an answer this one is the most likely.
It throws error because the callback doesn't get clear properly.
And it is caused by the return data from websocket.
normally it should return like
However, for some reason it might return something like
the very last response breaking into 2 pieces
And that causes the issue.
I don't think there is a way to bypass this without changing the source code.
I reported this on github repo as well at here
It turns out that I can just utilize invocation response to notify client to stop the hub. So it doesn't trigger racing issue.

Spring cloud performance tunning

I'm doing a performance test against a Spring Cloud application. When number of concurrent users exceeds 150, it starts to give "Forwarding error"
{"timestamp":1458685370986,"status":500,"error":"Internal Server Error","exception":"com.netflix.zuul.exception.ZuulException","message":"Forwarding error"}
Which parameter I should adjust to get rid of the error?
You should post your logs for the error, without that we can only guess what the exact error is. As Forwarding error reported by ZuulExcetption is a generic error.
See this link for the RibbonRoutingFilter.forward() method which actually reports this error. I'm adding the code here for the backup.
private HttpResponse forward(RestClient restClient, String service, Verb verb, String uri, Boolean retryable,
MultiValueMap<String, String> headers, MultiValueMap<String, String> params,
InputStream requestEntity) throws Exception {
Map<String, Object> info = this.helper.debug(verb.verb(), uri, headers, params,
requestEntity);
RibbonCommand command = new RibbonCommand(service, restClient, verb, uri, retryable,
headers, params, requestEntity);
try {
HttpResponse response = command.execute();
this.helper.appendDebug(info, response.getStatus(),
revertHeaders(response.getHeaders()));
return response;
}
catch (HystrixRuntimeException ex) {
info.put("status", "500");
if (ex.getFallbackException() != null
&& ex.getFallbackException().getCause() != null
&& ex.getFallbackException().getCause() instanceof ClientException) {
ClientException cause = (ClientException) ex.getFallbackException()
.getCause();
throw new ZuulException(cause, "Forwarding error", 500, cause
.getErrorType().toString());
}
throw new ZuulException(ex, "Forwarding error", 500, ex.getFailureType()
.toString());
}
}
As you can see that only viable place where the error can be generated is in command.execute(), where command is an instance of HystrixCommand. Here is a link for the execute() method in HystrixCommand.
Below is the code for backup.
public R execute() {
try {
return queue().get();
} catch (Exception e) {
throw decomposeException(e);
}
}
Here the queue() is a Future instance
Most common error that can occur with the Future is a timeout exception. Since here Future instance queue() is not bound by any timetout value, it can go on waiting for ever.
However most of the time API which make use of Future have a thread monitoring the time they take and they interrupt it after a certain period of time. Same is done by Ribbon.
If yours indeed is a timeout issue then an easy solution is to increase Ribbon timeout value by using following property.
ribbon.ReadTimeout=10000
//or
<client-name>.ribbon.ReadTimeout=10000
Time out majorly can occur if the tomcat server which hosts the service which is proxied by the Zuul has too much load. It's whole thread pool is exhausted thus resulting in the next requests having to wait for long time.
This can probably be alleviated by change the number of threads that your service tomcat has by using following property.
server.tomcat.max-threads=0
By default it's set to 0, which leaves it to the embedded server's default. In tomcat's case it's 200. See the reference maxThreads property in tomcat.
Note: To increase the thread pool size we have to make sure that the machine has that capacity to provide resources if that many threads were to be in execution simultaneously.

Provide UserName<553> message in quick

I have created an application for FIX transactions using QuickFIX c++ API. The application is connecting to the server but the server sends "Provide UserName<553>" message. I looked for and result and found that i need to add username and password to the toAdmin method created this following code to in order to achieve that
void Application::toAdmin( FIX::Message& message, const FIX::SessionID& sessionID)
{
if (FIX::MsgType_Logon == message.getHeader().getField(FIX::FIELD::MsgType))
{
FIX44::Logon& logon_message = dynamic_cast<FIX44::Logon&>(message);
logon_message.setField(FIX::Username("my_username"));
logon_message.setField(FIX::Password("my_password"));
}
}
But then it throws and Exception. Please suggest what to do
remove this line and exception is handled
FIX44::Logon& logon_message = dynamic_cast<FIX44::Logon&>(message);
after that Put it
message.setField(FIX::Username("my_username"));
```````
message.setField(FIX::Password("my_password"));

Invalid attempt to call FieldCount when reader is closed

The error above occurs when I try to do a dataReader.Read on the data recieved from the database. I know there are two rows in there so it isnt because no data actually exists.
Could it be the CommandBehavior.CloseConnection, causing the problem? I was told you had to do this right after a ExecuteReader? Is this correct?
try
{
_connection.Open();
using (_connection)
{
SqlCommand command = new SqlCommand("SELECT * FROM Structure", _connection);
SqlDataReader dataReader = command.ExecuteReader(CommandBehavior.CloseConnection);
if (dataReader == null) return null;
var newData = new List<Structure>();
while (dataReader.Read())
{
var entity = new Structure
{
Id = (int)dataReader["StructureID"],
Path = (string)dataReader["Path"],
PathLevel = (string)dataReader["PathLevel"],
Description = (string)dataReader["Description"]
};
newData.Add(entity);
}
dataReader.Close();
return newData;
}
}
catch (SqlException ex)
{
AddError(new ErrorModel("An SqlException error has occured whilst trying to return descendants", ErrorHelper.ErrorTypes.Critical, ex));
return null;
}
catch (Exception ex)
{
AddError(new ErrorModel("An error has occured whilst trying to return descendants", ErrorHelper.ErrorTypes.Critical, ex));
return null;
}
finally
{
_connection.Close();
}
}
Thanks in advance for any help.
Clare
When you use the Using in C#, after the last } from the using, the Connection automatically close, thats why you get the fieldcount to be closed when u try to read him, as that is impossible, because u want those datas, read then before close the using, or u can open and close manually the connection, by not using the (using)
Your code, as displayed is fine. I've taken it into a test project, and it works. It's not immediately clear why you get this message with the code shown above. Here are some debugging tips/suggestions. I hope they're valuable for you.
Create a breakpoint on the while (dataReader.Read()). Before it enters its codeblock, enter this in your Immediate or Watch Window: dataReader.HasRows. That should evaluate to true.
While stopped on that Read(), open your Locals window to inspect all the properties of dataReader. Ensure that the FieldCount is what you expect from your SELECT statement.
When stepping into this Read() iteration, does a student object get created at all? What's the value of dataReader["StructureID"] and all others in the Immediate Window?
It's not the CommandBehavior.CloseConnection causing the problem. That simply tells the connection to also close itself when you close the datareader.
When I got that error, it happened to be a command timeout problem (I was reading some large binary data). As a first attempt, I increased the command timeout (not the connection timeout!) and the problem was solved.
Note: while attempting to find out the problem, I tried to listen to the (Sql)connection's StateChanged event, but it turned out that the connection never fall in a "broken" state.
Same problem here. Tested all the above solutions
increase command timeout
close the connection after read
Here's the code
1 objCmd.Connection.Open()
2 objCmd.CommandTimeout = 3000
3 Dim objReader As OleDbDataReader = objCmd.ExecuteReader()
4 repeater.DataSource = objReader
5 CType(repeater, Control).DataBind()
6 objReader.Close()
7 objCmd.Connection.Dispose()
Moreover, at line 4 objReader has Closed = False
I got this exception while using the VS.NET debugger and trying to examine some IQueryable results. Bad decision because the IQueryable resulted in a large table scan. Stopping and restarting the debugger and NOT trying to preview this particular IQueryable was the workaround.