Datasnap remove expired sessions Delphi - delphi

an app created for the mechanics of a company is controlled through the datasnap windows service active on the server. Now, these mechanics are often on the road and disconnect from the server. When the technician opens the app again and connects to the service, a new session is created and the old session is not deleted. This results that there is an accumulation of expired sessions that are not removed. how can I make sure the expired sessions are removed?
If I forgot some information please let me know and I add it to the question.

After some documentation form embarcadero I've added the following to my DSTCPServerTransport.OnConnect event:
Event.Channel.EnableKeepAlive(30000);
where 30000 the amount of milliseconds is.
on my client-side i added the following to my FDConnection.Onrecover event:
AAction := TFDPhysConnectionRecoverAction.faRetry;
This solves my problem with the unused sessions.

Related

Acumatica - Users are receiving "Session Expired"

Web Users are receiving "Session Expired" when using Acumatica ERP, I have made the following changes to the Web Config file as per documentation:
changed the ReminderRequestPeriod
report Time-out settings
Query Time-out settings
Depending on when/where the users are receiving the timeouts it could be various items.
If the timeout is happening at a consistent duration, then chances are the users are hitting the standard ASP "Session" timeout.
In the web.config file look for the "sessionState" tag and see what the value in "timeout" is. This is in minutes. Increasing this value can increase the amount of time before a users "session" times out.
When modifying this value, you should also look to the "forms..." tag and see what the "timeout" there is set to. This is the duration of the forms authentication duration. These should match or be close or you'll have the authentication timing out before the actual session does.
If you are having random issues (timeouts occurring at various times to various users or multiple users at the same time), one thing to look at is the Eventlog on the server. If there is a problem where the IIS Application pool is recycling (does this by default) or if it is crashing, the end user sessions are not persisted and will show the timeout message.
If it's a recycling issue, you can adjust the the amount of time before it recycles in the Application Pool.
If it's an issue with the pool crashing, there will be an event log showing the crash to help isolate where this is occurring. I had a customer who had this issue recently. After applying some updates they never restarted the server which was causing periodic application pool crashes. Running low/out of memory can do this as well.
These won't guarantee a fix however it might help you isolate the cause of the timeouts
I have similar issue. In my case it worked increasing available memory at web server
Also, remember that if your site was upgraded, you may need to reset your license keys. (you will probably need to contact Acumatica to do this)
We have had clients where their license became invalid after upgrading to a newer version and then only 2 users could log in and if a 3rd user logged in one of the other users received the "Session Timeout" error.

How to check if user has bought consumable item?

First, thanks everyone.
Prerequisite:I am providing consumable items in my application.
product:
List item
User purchase the item by iap.
before my application received the updatedTrancactions(Transaction),Network is disconnected.
So my server don't have data to verify the receipt. the user also can not get the "Virtual currency".
Would anyone tell me how to solve this problem,or give me some tip. Thanks very much.
its the standard client-server problem. In case the connection between client and server is severed (due to timeout or other reasons), common way to do it is to retry the request. But if your API calls are not Idempotent and calling an API multiple times can affect the state of your system that many times then we have to resort to do something more clever. Some options you have -
Have a local database. When a purchase happens, then first update the state in you local DB. Late lazily sync the DB from client to server, I hear coredata or sqlite is excellent. User is not aware of this and since DB is local the UI will be extra snappy for the user.
Second approach is - in case of a failed HTTP call. You keep retrying till the call succeeds.
Incase the API is non-idempotent, then you need to have a concept of a token. i.e. a API call with the same token called multiple times is first checked on the server-side if the initial call was a success only if it was a failure execute again. ex. this is very important in banking solutions. Imagine multiple debits from your bank account due to timeouts and someone programmed to keep retrying!
This is all I am able to think of right now. Give it a spin and tell us what worked for you...

Delphi XE2 Datasnap Session Management - get session information after page reload

I am trying to determine how to retrieve session information using a Delphi REST DataSnap server.
I know that, when on the same client page, you have access to the current thread session using the TDSSession method GetThreadSession.
What I want to do, however, is store data in the session (putData) and still be able to retrieve it when the user moves from page1 to page2. At present, if the user moves to a different page, the session is lost and a new one is created, thus loosing the data in the session that I had previously set.
I have tried playing with TDSSessionManager.SetThreadSession(sessionid) - but I cant seem to get it working.
I've reviewed the much acclaimed Marco Cantu white paper, however, it doesn't provide a solution to this issue.
Any help I can get on this would be great - even if its just 'hey, this topic is covered in book X'.
Thanks!
The TDSSessionManager.SetThreadSession(sessionid) works with Session.sessionname.
Plus make sure your Lifecycle is set to Session (as stated by tondrej).
If you reconnect your client. a new session is started. So you want to keep your Datasnap connection open.
Or you can set the lifecycle to Server and mannage the client-sessions yourself.
Edit: Rest Servers are Stateless. So you need to store the page you are on on the Client. And Query the needed Page from the Server
You have to tweak the client side JavaScript to use a cookie to store session info.
See the last part of JavaScript Client Sessions
If you want to keep server side objects active for the session use the Session life cycle.
I believe what you need to do is set LifeCycle property of your TDSServerClass instance to Session (stateful). From your question it seems you are currently using Invocation (stateless).
Well, in Datasnap REST (GET, POST, DELETE, PUT) if you set your TDSServerClass to session, as is a REST in this case session is the same as invocation, is stateless (http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Server_Class_LifeCycle#REST_Clients). It is right, you give the oportunity to all kind of clients to use your datasnap server with JSONs for example.
You need to create your owner model to session control to your REST server, or look for some framework to do this. In my case I use custom objects on lifecicle server (some cases with database too), and using tokens on request headers and other informations, I know if is the same client and I control too when the token expires and need to do new login, for exemple and I can give much more security too as on PUT resquests, only on records gave to client (it is only one case, but there are much others...). You need to resolve other way, not with classic way using TDSSession.

How to enable cookies for a pseudo-browser in Delphi?

I was testing an app from Marco Cantu's Delphi 2009 Handbook. This app, called AnonAjax (page 200), has some interesting features to recognize certain elements from a Web page and list them. This app uses anonymous methods with an internal Indy HTTP client component used to access to a given URL. As part of this app's functionality, it loads the first image listed. That's great, but with a Web page using cookies it does not load the image properly. I've tried with AllowCookies=true but it does not work. How can I enable cookies for this app?
you can attach a cookie manager (indy component) to the indy http client component.
Indy 10's cookie management is currently undergoing a major rewrite to address many issues that it has. It is likely that you are encountering a situation where the version of Indy you are using is either rejecting the server's cookies incorrectly, or is not sending them back to the server correctly. Unfortunately, I do not have an exact ETA as to when the new cookie management code will be ready for public use, but it is very close, possibly by the end of this month if time permits.

How can I update a DataSnap server while clients are still connected?

We use stateful DataSnap servers for some business logic tasks and also to provide clientdataset data.
If we have to update the server to modify a business rule, we copy the new version into a new empty folder and register it (depending on the Delphi version, just by launching or by running the TRegSvr utility).
We can do this even while the old server instance is running. However, after registering the new version, all new client connections will still use the currently running (old) server instance. All clients have to disconnect first, then the new server will be used for the next clients.
Is there a way to direct all new client connections to the new server, immediately after registering?
(I know that new or changed method signatures will also require a change and restart of the clients but this question is about internal modifications which do not affect the interface)
We are using Socket connections, and all clients share the same server application (only one application window is open). In the early days we have used a different configuration of the remote datamodule which resulted in one app window per client. Maybe this could be a solution? (because every new client will launch the currently registered executable)
Update: does Delphi XE offer some support for 'hot deployment' (of updated servers)? We use Delphi 2009 at the moment but would upgrade to XE if it offers easier implementation of 'hot deployment'.
you could separate your appserver into 2 new servers, one being a simple proxy object redirecting all methods (and optionally containing state info if any) to the second one actually implementing your business logic. you also need to implement "silent reconnect" feature within your proxy server in order not to disturb connected clients if you decide to replace business appserver any time you want. never did such design myself before but hope the idea is clear
Have you tried renaming the current server and placing the new in the same location with the correct name (versus changing the registry location). I have done this for COM libraries before with success. I am not sure if it would apply to remote launch rules through as it may look for an existing instance to attach to instead of a completely fresh server.
It may be a bit hackish but you would have the client call a method on the server indicating that a newer version is available. This would allow it to perform any necessary cleanup so it doesn't end up talking to both the existing server instance and new server instance at the same time.
There is probably not a simple answer to this question, and I suspect that you will have to modify the client. The simplest solution I can think of is to have a flag (a property or an out parameter on some commonly called method) on the server that the client checks periodically that tells the client to disconnect and reconnect (called something like ImBeingRetired).
It's also possible to write callbacks under certain circumstances for datasnap (although I've never done this). This would allow the server to inform the client that it should restart or reconnect.
The last option I can think of (that hasn't already been mentioned) would be to make the client/server stateless, so that every time the client wants something it connects, gets what it wants then disconnects.
Unfortunately none of these options are the answer you want to your question, but might give you some ideas.
(optional) set up vmware vSphere, ESX, or find a hosting service that already has one.
Store the session variables in db.
Prepare 2 web boxes with 2 distinct IP address and deploy your stuff.
Set up DNS, firewall, load balancer, or BSD vm so name "example.com" resolves to web box 1.
Deploy new version to web box 2.
Switch over to web box 2 using whatever routing method you chose.
Deploy new version to web box 1 if things look ok.
Using DNS is probably easiest, but it takes time for the mapping to propagate to the client (if the client is outside your LAN) and also two clients may see different results. Some firewalls have IP address mapping feature that you can map public IP address and internal IP address. The ideal way is to use load balancer and configure it to 50:50 and change it to 100:0 when you want to do upgrade, but it costs money. A cheaper alternative is to run software load balancer on BSD vm, but it probably requires some work.
Edit: What I meant to say is session variables, not session. You said the server is stateful. If it contains some business logic that uses session variable, it needs to get stored externally to be preserved across reconnection during switch over. Actual DataSnap session will be lost, so when you shutdown web box 1 during upgrade, the client will get "Session {some-uuid} is not found" error by web box 1, and it will reconnect to web box 2.
Also you could use 3 IP addresses (1 public and 2 private) so the client always sees 1 address , which is better method.
I have done something similar by having a specific table which held my "data version". Each time I would update the server or change a system wide global setting, I would increment this field. When a client starts it always checks this value, and will check again before any transactions/queries. If the value was ever different from when I first started, then I needed to go through my re-initialization logic, which could easily include a re-login to an updated server.
I was using IIS to publish my app servers, so the data that would change would be the path to the app server. I kept the old ones available, to respond to any existing transactions that were in play. Eventually these would be removed once I knew there were no more client connections to that version.
You could easily handle knowing what versions to keep around if you log what server the client last connected too (and therefore would know about).
For newer versions (Delphi 2010 and up), there is an interesting solution
for systems using the HTTP transport:
Implementing Failover and Load Balancing in DataSnap 2010 by Andreano Lanusse
and a related question for the TCP/IP transport:
How to direct DataSnap client connections to various DS Servers?

Resources