We have had this error recently reported by our clients and we on't know how we can fix this. We are using Delphi XE6 to develop our application and it connect to Firebird (v2.5) database as back-end. We also have used IBObjects for working with Firebird database in Delphi.
We have managed to replicate the error on the dev machine by stopping Firebird windows service before running a query but we haven't found a way to detect the connection lost in the code (e.g. by having an event) so as we don't know when this happens so we cannot reconnect to the database in the code either.
By the way, this is full error message if it helps:
ISC ERROR CODE:335544721
ISC ERROR MESSAGE:
Unable to complete network request to host "BON-VFS-01".
Error writing data to the connection.
Any help really appreciated.
From IBOBjects FAQ
Is there a way to detect a lost connection and try to reconnect
automatically, without user action?
Hook into the OnError event and look for the ERRCODE that denotes a
lost connection. Then, you can take whatever action you deem necessary
to deal with the problem. If the connection is lost you need to do a
disconnect and then connect again.
And from one of the base members of the IBObjects:
However, perhaps the "something" you are missing is that, if the
connection is broken by an external cause, the client application has
no way to know that it is not still connected. Its first knowledge of
that fact will come the next time it tries to access the server. The
API will report "Connection lost to database" and return GDSCODE
335544741, which is identified by the constant
isc_lost_db_connection.
At the point where this exception occurs, the TIB_Connection still
thinks it is connected - the Connected property will be true. If you
try to reconnect by calling Connect, you will get an IBO exception.
It is necessary to call Disconnect. This does not simply reset a
property. The Disconnect method performs all of the necessary cleanup
to invalidate the broken transactions and cancel any now invalid
postings, datasets and caches. Once Disconnect has completed its
work, you can then place a Connect call inside a retry loop and
attempt to get going again.
I do not know of a working example, but the simplest way to deal with
this is to write a RestoreConnection handler procedure that you can
call from your IB_Session.OnError handler whenever argument ERRCODE
returns isc_lost_db_connection.
Have your RestoreConnection procedure do whatever you need to do,
trying to call Connect and handling the exception that occurs if the
request fails, until no exception occurs. Test the Connected property
after each iteration. When Connected is finally True, you are in
business. You can drop out of the retry code and inform the user that
the connection has been restored - perhaps with a sound and/or a
message in the status bar, to avoid having to show a dialog box that
she has to respond to. (if you like the idea of sound and status bar
cues, you could devise "connection lost" warning sound and status bar
message code to run at the beginning of your handler procedure as
well...)
If these broken connections are a frequent occurrence, you might like
to consider making a distinctive custom cursor that you can display
while your procedure is running, and enclose the retry code in a
non-yielding BeginBusy...EndBusy block with UseCursor enabled and
BusyCursor set to use this special cursor image.
And if re-establishing a connection is likely to take a long time, or
to be temporarily impossible, you would need to provide the ability
for the user to intervene and choose not to keep trying. You can use
the session timer for this, enclosing your "busy" block inside
another iterative block the prompts the user to "Cancel" or "Keep
Trying", at reasonable intervals.
Source
Check out if their database file is located on mapped network drive. Even if database file path appear to be local to file system, when using embedded Firebird server, function isc_attach_database will return error code 335544721 on attempt to establish connection. Exactly that was happening on my VirtualBox guest Windows XP when I first share entire host D drive and then mapped it again as D drive in virtual guest OS.
Workaround will be to move database file to local partition drive.
check your query length
max query length is 8191 chars UTF-8
its solved my problem
connect your pc to the internet, and the problem will be fixed,but i don't how it works
Related
I have an Grails application which does the following:
When a request is received from the client side, the server starts creating a zip file for that request and sends it back to the client machine. The amount of time the server takes in order to create the zip file is very high, and even though the connection is lost between the client and the server, the zip file is generated by the server continuously for 3 days or so, using 100% of the CPU, and sending the response somewhere, probably a dead-end.
I tried looking out a way to resolve this, and I find that socket programming is a way in order to detect the connection loss.
This question may look broad, but I just want to know the ways, a connection loss can be found out, so that I can dig around that approach and find out the solution.
Check if the object holding the results of the connect() method is null.
You can also wrap a try catch statement around the code that attempts the connection, and print out the exception if it fails so you know where/what happened.
I am loosing my patience with "delay write failed" errors. It silently disconnects the database from the application so nothing gets saved in the database while using it. Is there a way to detect the occurrence itself so I can flash a warning ? Or perhaps monitoring the connection itself for a disconnection ? Everyone seems to miss the balloon tip from the Windows XP so I figured to flash a more visible warning that the application must be restarted. It seems Microsoft has found a way to force people to upgrade....
I suppose this could be done with a timer and constantly check connected users:
cxlabel1.Caption := IntToStr(DataModule2.ABSDatabase1.GetDBFileConnectionsCount);
But I was thinking more of checking/detecting for the occurence itself. Is there something in Delphi that can detect this?
I would like to hear your ideas on this...
Putting this as an answer because the comment length is limited.
I have seen this before. IIRC, the problem you have is that the Delayed Write Error is an OS error, it has nothing to do with your application. Windows has already told you that the write has been committed correctly to disk. You would have to try and hook into the OS errors to see when this is happening.
You need to get the network issues resolved because that's where the problem is. In our situation it was a faulty router that was causing the problem.
It's unfair to expect users to check for the error message and then handle it. They could be out at lunch when it occurs as it's not immediate. They also have no way of know what has been saved and what hasn't. It's only a matter of time before your database is corrupted.
The problem with a timer is that it might tell you everything is fine because it triggers after the network resolves the problems.
A far better approach would be to switch to a Client/Server database. You can do this by setting up your own server that listens for web service or another remote call or switch to a database that supports client/server instead of using a file based database. This will tell you immediately when there is a problem with the save of data.
I have an exception handler that runs when my code crashes, but I also need to send a msg to the server (parse.com) when this happens to let the server know the player has stopped playing,
void onUncaughtException(NSException *exception)
{
NSLog(#"uncaught exception: %#", exception.description);
[self playerLoggedOut];
}
The playerloggedOut line gives the error of undeclared identifier self.
How can I run the playerLoggedOut method when the exception happens?
How can I run the playerLoggedOut method when the exception happens?
You're not going to be able to start some lengthy process like establishing a network connection and sending a message. Your best strategy might be to save the information and send it when the app starts up again so that the server can update its records or whatever. Alternatively, have the client check in with the server every t seconds; if the server doesn't hear from the client within some interval like 2t, it assumes that the client has stopped functioning.
First of all: self is unknown, because you are not in a method, but a function. Functions do not run in an object context, therefore do not know self.
As mentioned before by Caleb, you should have a watch dog on server-side that automatically logs a player out, if the server gets no messages from the client for a while (in terms of seconds). To prevent from being logged out automatically, when the user is deactive (but still playing), you can implement a heart beat on the client using an instance of NSTimer.
As others have stated, don't try to do expensive things like talk to the Parse server in your exception handler.
In regards to what you are actually trying to achieve, you might want to re-think your architecture.
In the sometimes-connected world of mobile devices you will have your connection come and go. Instead of a boolean flag of IsLoggedIn, consider a UTC Date Time of LastUserActivity, and use a rule that says they are considered logged in if that last activity is in the last 5 minutes, or whatever is suitable.
If all access to Parse is done via Cloud Code then you could easily add a function call that sets the LastUserActivity to each method, then you can also avoid issues with time sync since you'll always be using the server's clock.
If you want to get a list of all online users, you can then just query for where LastUserActivity is greater than 5 minutes ago (or whatever limit you set).
I'm trying (with a lot of help from this community) to put together my first client/server app.
I am using Indy 10 and Delphi Xe2, but suspect my problem does not lie with those, but rather with how soockets work (wizardy and black arts, if you ask me).
Because I often hit breakpoints of exceptions and step through my code before pressing Alt+F2 to halt, my next runs often hit exception "already connected" and eventually I get "too many connections".
How can I tidy this up?
(also, does anyone have a demo which uses try ... except, ratehr than try ... finally as in the Indy demos?)
"already connected" occurs on the client side when you call Connect() while Connected() still returns true. That usually occurs if you disconnect and leave unread data in the IOHandler.InputBuffer. Try clearing the InputBuffer before reconnecting. This is commonly encountered, so a near-future update to Indy may address that issue.
"too many connections" means that you set the server's MaxConnections property to a positive non-zero value and that many simultaneous clients are already connected to the server when a new client tries to connect. If you do not think that you are making that many simultaneous connections, then it usually means that you are not managing the connections correctly in your server code so disconnected clients get cleaned up correctly. The most common cause of that is putting exception handlers in your code that catch and swallow Indy's internal exceptions to itself. If you do catch exceptions, be sure to re-raise any that derive from EIdException and let the server handle them internally.
I have a service written in Delphi 2007 in which I'm trying capture any unknown exceptions. Assigning a method to the on exception doesn't seem to work ('Forms.Application.OnException:=UnknownApplicationException'). The 'UnknownApplicationException' doesn't appear to get called - I attribute this to the fact that there is no form in the application so the method never actually gets assigned. Aside from this, I've also tried creating an exception on a timer (after commenting out 'Forms.Application.OnException:=UnknownApplicationException' so that it does not interfere). The timer triggers 60 seconds after the service has started up:
procedure TProcessScheduler.Timer1Timer(Sender: TObject);
begin
try
Raise Exception.Create('THIS GIG SUCKS');
except
LogEvent(Name,rsUNKNOWN_EXCEPTION,EVENTLOG_AUDIT_FAILURE,0);
ExitCode:=-1;
Halt;
end;
end;
The exception never seems to get captured - the service starts up and after 60 seconds when this timer triggers, I hear a windows error sound but don't see any error dialog - perhaps this could be due to the fact that the application is a service? The 'Halt' never gets called and the application keeps running (i assume its waiting for someone to click ok on the invisible error dialog that it created). Any ideas why the code under the 'except' doesn't get called? Thanks in advance! KP
Reassigning Forms.Application.OnException is a bad idea, as TServiceApplication.Run() does this itself. You either do it before, then your assignment won't have an effect, or you do it afterwards, in which case you remove the exception handling mechanism that has been put into place.
If you leave the handling in place, then all exceptions will be logged to the Windows Event Logger, which seems a reasonable thing to do from a service.
A couple of notes:
As you are raising an exception within a try-except block, it should not trigger any Application.OnException handler, simply because the exception isn't unhandled.
How have you determined that the Halt doesn't get called? Does the exception get logged through your LogEvent?
In a Service application ExitCode and Halt don't function the way you would expect them to in a normal windows application. A service isn't stopped by calling halt, it should be stopped by going through the Windows' Service Control Manager.
If the except part of your try-except block is indeed not reached, it means that Windows has cut in because something has happened that it isn't happy with. That could be something in the LogEvent method you are calling. If that shows a dialog or if that raises an exception as well, the ExitCode and Halt won't be reached.
A service doesn't normally have a desktop associated with it, so showing dialogs isn't going to work.
If you need the service to show dialogs (bad idea by the way, services are intended to run without user interaction), you need to make it interactive and have it run under another user account than the normal "system" account that services run under. You do this through the services manager.
Why are you setting Forms.Application? AFAIK a service uses the Application variable declared in SvcMgr, which is declared as:
var
Application: TServiceApplication = nil;
Moreover a service should not display any dialog, it may not have access to the user desktop, and your dialog will hang the service. There are ways to display a dialog anyway, but services could also run when no human user is watching the screen.
Log events to the event log (or if you don't like it to a file, but the event log has several useful features, including remote access).
I create my own version of the SvcMgr.pas file to eliminate the in-place hook to the Application global exception handler so that I can instantiate my own. I do this because 1) I could find no other simple way of doing this, and 2) since this unit is a stand-alone unit that is only included with Windows Services then the effect on other units is minimal. You can download the code from my web-site to see how this works.