I am working on a application where many employees may login to the system to solve customer complaints. If one employee clicks "Start" button for the complain, the record should be freezed. By freezed I mean it should not appear on other employees screen (when the screen updates on their machine using Ajax). Further it shouldn't appear only for a certain amount of time duration. If the employee doesn't response to the complain within few minutes it should again appear in the queue of complaints.
How do I manage this time duration? I have one approach where one the user clicks on "Start", I could store that item in Cache object and it's only valid until it's expiry comes. Then when other employee's screen refreshes I only show those items that are not attended and not present in Cache. If it is present in Cache it means it is being attended by someone. Am I going on the right track? Or is there any better way of doing it?
One thing you could do is have a 'lock' column in the database, and have that column be a DateTime column.
When a user clicks 'Start', note the time in that column.
When retrieving records for display, filter out any which have a non-null value in the lock column, or who's value in the lock column is from at least x minutes ago (which you can calculate using math on the GetDate() function).
The easiest way to do this is to have a column called 'RecordStatus' or something like that, which you can set to a special value to indicate it is still being created or modified.
This forces you to modify all your queries to specifically exclude records that have that status, but in the long term it works better and is more reliable than any type of database or application-level logical locks.
We've solved this at my company in two situations, independently, using some variation on a "record lock" DB record. In one system the locking record is created when the record enters the "queue" as a new item; in the other, the locking record is created when a user picks up a record out of the queue.
Either way you slice it, as of when a user's copy of your software opens a queue record for work, a locking record should be in the DB with some uniquely identifying information about your user written to it. It should be unique to the record being locked, and maybe the lock level (meaning two locks of the same level cannot exist on the same record), and identifies the user who opened the record as "owning" it for the purposes of making changes. This locking record should persist as long as the user has the record open in his software.
The ability to "break" locks can be achieved by simply reassigning the lock to another user, coupled with regular polling of the locking object by the original locking user's software; if, at any time, the user no longer is the owner, the lock has been "broken" and the user has the option to reacquire the lock (breaking the other user's new lock) or simply move on.
Now, should the user's software crash, they will still own a lock on the record. It may also happen that the operation to remove the lock fails (this can happen in situations where the real data is in another DB and you cannot enforce a universal transaction). In such a case, you will need some mechanism to remove "orphaned" locks, or force the user to remove them. If the items being locked are time-sensitive, you will need to design multiple redundant levels of lock removal (perhaps a timed job that, once a minute, will break any lock older than X minutes or which is known to be "orphaned" because that user isn't logged in anymore).
Related
I know the difference between Data Reader and Data Set.
The DataReader is a better choice for applications that require optimized read-only, fast and forward-only data access.
The Data set is better for Application wherein you can get all the data and update it according to your needs at application level and submit the change to the database.
Please clear if there is anything wrong in my understanding.
Now I had an interview there a person asked me. Is datareader or Connected architecture good for application like ticketing system. Basically she meant were many user might be trying to update the same table. Thus the concept of Concurrency comes.
We can Use Disconnected architecture to check for concurrency and let only one user update the table at a time. But dont know how it happens in terms of connected Architecture. Does the connection to the data base and particularly to the table concerned would that make only one user do the update while others who try to hit later wont be able to do that.
Wont it affect the performance if all the user have opened a connection as database will reach bottle neck.
I hope i will get the answer to understand them.
I think its not a matter of which one is better, since data is already old/invalid once it reaches the client. Showing a table of reservations can be useful to get a rough view of what reservations are made, but it might be totally different within the next second. You want to eliminate race conditions. A good architecture is necessary to start with.
One way to do this is to 'reserve' the ticket [1]. The application asks to get a ticket that is available given the matched criteria. At this point its a known fact on whether the ticket is available or not. If it was available, it was already reserved as well. This avoids multiple reservations for one ticket. The next reservation (same operation/action) will result into a different ticket being reserved. You can always add information to this ticket later (such as the owner of the ticket and his/her information) if required. Tickets that do not have information attached to it, will timeout after a certain amount of minutes and will return back to the pool. These tickets can be 'reserved' again [1].
[1] To avoid multiple assignments, use optimistic locking.
To answer the question, I would say DataReader. It keeps the database communication to a minimum (load and locks), so it can handle updates as fast as possible. Just keep in mind picking one over another doesn't solve concurrency problems. It's the total solution that matters.
Example
I don't know the requirements, but since it's an interview question I'll give an example. Don't take this as a golden rule, but off the tip of my head it would be something like this:
(if required) First the user is shown a screen that there are tickets left in the system that can be reserved. Open a connection, and a reader to read the amount of tickets available for reservation. Close the reader and connection. The user proceeds to the next screen.
SELECT COUNT(*)
FROM [Tickets]
WHERE ([LastReserved] IS NULL OR [LastReserved] <= DATEADD(MINUTE, GETDATE(), #ticketTimeout))
AND [TickedAssignedToUserId] IS NULL;
The user requests an x-amount of tickets and proceeds to the next screen. At this moment the system checks with optimistic locking if there are enough tickets available. Simply open a connection (with transaction!) and execute the following query:
UPDATE TOP(#numberOfTicketsRequested) [Tickets]
SET [LastReserved]=GETDATE()
WHERE ([LastReserved] IS NULL OR [LastReserved] <= DATEADD(MINUTE, GETDATE(), #ticketTimeout))
AND [TickedAssignedToUserId] IS NULL;
The number of rows affected should be the same as #numberOfTicketsRequested. If this is the case, commit the transaction and get it's ticket identifier. Otherwise rollback and tell the user that there are no tickets available anymore. At this point we need the record information, so you might want to get the identifier as well.
At this point, the user gets #ticketTimeout amount of minutes time to enter their user details. If done correctly, the following query can be executed:
UPDATE TOP(#numberOfTicketsRequested) [Tickets]
SET [TickedAssignedToUserId]=#userId
WHERE [TicketId]=#Id AND [LastReserved]=#lastReserved AND [TickedAssignedToUserId] IS NULL;
If the user took longer than, say 10 minutes, and somebody else requested the same ticket again, then the LastReserved timestamp has changed. When the first user tried to reserve the ticket with their details, the update does not match the original LastReserved timestamp anymore, and the update will show not enough rows affected (=rollback). If it matches the number of rows affected, the user successfully reserved the tickets (=commit).
Note that no ticket information except for ticket identifiers have reached the application. Nor have I included user registration. No full tables are being passed, and locks are just being used minimally (just for two short updates).
We are developing a C# application that used to work as a single instance application. Now we need to change it to be a multi-user application, meaning the GUI front-end will be run on multiple workstations while accessing a single MS SQL Server 2008 R2 data store.
Part of the work this application manages is queue based, meaning there's a pool of workitems (the list of workitems is in a single SQL table) from which each user can "take" the next available workitem. What I want to accomplish are the following:
once a workitem is "taken" by a user, no other user should have access to it in any way (including reading) until the first user finished working,
handle timeouts (user goes home for the weekend while workitem is taken) and frozen clients (reset button is pressed on the station while workitem is taken).
I know this is a rather general question (much rather a research), so I'm not expecting a detailed solution, but useful links, best practices and/or some literature to read on the subject. Any help is really appreciated since I'm completely lost where to start.
I've seen this done with a transactional resource lock table or column. For example, you assign the record to someone (be it by setting a user ID or some other mechanism) and you simultaneously set a timestamped record as to when that resource was locked. When accessing the data, be it querying it or trying to update it, you first check this lock table/column to make sure it's available. If not, you don't take the changes.
This also supports timeouts then. If the timestamp is too old, the lock is released. You can automatically assumed release if the timestamp is too old, or you can write a scheduled service that will check for expired locks and unlock them. I'd prefer the second way, as it is less costly to check if a lock is there (boolean logic for row exists or if field value exists [i.e. is not null]). But I've seen it done both ways.
sorry for my bad english. I approached recently to programming in Visual C # and am not a expert programmer. After this short introduction, the important thing I need to implement a management competition on a record during editing operations. This means that having two computers at the same time using this software, the first that starts editing a record, have to "lock" the record so when and if, in the second instance of the program, an attempt to change the same record, a standard message will be displayed and the procedure is interrupted.
I actually use MySQL DBMS and the only thing I could do is to lock the record with "START TRANSACTION" until I COMMIT or close the connection. The problem is that I don't know how to check if there is an active transaction or some kind of block to stop the procedure and this means that the second instance of the program is completely blocked until they release the records from the first instance. Solutions? Thank you for your attention.
Well, in general it's a bad design to physically lock a record while a user is working on it. Database locks are supposed to be short. There should be only code execution between starting the transaction and committing it, but absolutely no user interaction.
You can google "Optimistic locking vs. Pessimistic locking" to understand more about the subject.
If you must use pessimistic locking, you will have to implement some sort of a smart software locks instead of database locks. For example, you could add two fields for the Current_Edit_By and Current_Edit_Time. When a user start editing a record, you fill in these fields with the user id and the current datetime. When another user try editing the same record, you check these two fields and if there are values there then you display an error.
Of course you will need to implement a mechanism to clean locked record automatically if the user disconnect from the database without committing the record. Hence the datetime field (To clear locks older than 30 minutes for example, as long as the connection is no longer there).
I wrote a multi user app in c# some time age using SQL Server 2005 express as back-end.
I have a Orders collection. In order to use this class you would need to instantiate it and just call the Load(CustomerCode) method in order to populate the collection with the specified customers`s orders.
My question:
How do I enforce concurrency, so that only 1 user can request a Orders collection for a specific customer? When the user is done with the object(when the object is set to null),
I will need to make it available again.
You need to implement the Pessimistic Offline Lock pattern.
Essentially you have a table that you put records in that represent a "lock" on records in other tables. When you want to edit a record, you check to see if there's a lock in the lock table first, and react accordingly in your domain logic/UI.
It doesn't have to be a database, it could be an in-memory cache. When I say "table" in my example, I mean a logical table, not necessarily a database one.
Pessimistic Offline Lock prevents
conflicts by avoiding them altogether.
It forces a business transaction to
acquire a lock on a piece of data
before it starts to use it, so that,
most of the time, once you begin a
business transaction you can be pretty
sure you'll complete it without being
bounced by concurrency control.
I am the lead developer on a commercial Windows app (c#). A new requirement is to track customers who abuse the license.
For example: Let's say a customer purchases a 10 user license agreement, i.e. 10 simultaneous users at any given time.
I need to be able to report, looking back at history, all the times that customer had more than 10 users logged in at the same time.
I already have a User table with columns: userid (primary key), pw, lastLogin, lastLogout.
I was thinking about creating a a new 'logging' table in which a new row is added each time a user logs out...columns might include:
LogId, UserId, LoginDateTime, LogoutDateTime
...and then I would have a history of every time a user logs in/out of the app...
but I'm not sure if this table design will lend to efficient calculations for reporting...whether I use SQL or c# to perform the calculations does not matter to me, as long as it is reasonably fast...
Hoping someone might have a good idea about how to better design this table so that I can quickly calculate any/all points in time when the customer exceeded the license limit.
Note: I do not want to block the 11t, 12th etc. user from using the app...the requirement is to display a warning message to the user but to allow him to continue working...
Think about starting and ending sessions as events that need to be recorded. You create a single table to record these events.
So, a session that starts and ends will have two entries in the table - one for the session start and one for the session end. You only ever add records to the table, never modifying previous records. The table can keep track of the number of open sessions very simply now by adding a "session count" field to the record that is incremented from the previous record's session count value when a session start event occurs and decremented when a session end event occurs.
The "session count" column now gives us a piece-wise continuous function over time of the number of concurrent sessions.
Example data:
SessionId EventType .... your session data here ... SessionCount
1. 1 Login ................ 1
2. 2 Login ................ 2
3. 3 Login ................ 3
4. 1 Logout ................ 2
5. 4 Login ................ 3
6. 4 Logout ................ 2
7. 2 Logout ................ 1
8. 3 Logout ................ 0
9. 5 Login ................ 1
10. 6 Login ................ 2
Things to worry about:
You must make sure you pair begin/end events, so in the event of any failure, session end events must still be generated.
Do you need the table to be tamper proof? If so, I have a technique for that also.
EDIT: please note that where I put "your session data here", I really meant "your session event data here". Information such as a time stamp would go in here. Another table should be used to track session information common to both events, such as the identity of the user that owns the session (use the same SessionId key for both tables).
A different option is to create a user sessions table. When a user logs in, insert their session into the table. When they log out, delete it. That way you always have an easy way to find out how many users are connected.
Then you can create a trigger on insert (and maybe delete) and you can log from there based on the session count. If you log delete as well you have an idea of the length of time they used an excessive amount of users.
Also keep in mind that you'll have to clean up orphaned connections appropriately.
I would be wary to implement something like license checking this way, because (as noted in Daniel's answer already, you don't get logout event in case your app crashes, or possibly even if user quits it in a specific way (End Process from Task Manager, ALT+F4, instead of going through File | Exit, etc).
So you could conceivably have a growing portion of dead sessions as users use the application. Not only you could get wrong data and impression about your users, but more importantly, they would grow frustrated by receiving warning messages they don't deserve. And if you try to tell them they are violating the license when they are actually not, they could become quite affronted. A good way to lose customers.
I would say a reasonable license checking scheme requires central server outside customer control, and for customer to have Internet access. It could go something like this:
on starting application, program
informs license server of a new
session;
during application work, program
periodically (let's say 1x 5mins or
so) sends a status signal to license
server;
on exiting program normally, it
sends session end signal to license
server;
if no status signal is received in
10mins from program, session is
considered terminated by license server
anyway.
Note: This is a problem that's been dealt with before. The best option I've seen is to maintain an MRU stack of user activity by unlogged-out users (in this case depth 10), and derived from database transaction activity - SELECT TOP 10 DISTINCT usercode FROM atable WHERE (most recent transaction type wasn't "log off") ORDER BY timestamp DESC. As soon as someone accesses the system that isn't among the most recent 10, you have two options. You allow them to log in, and bump the oldest to logged out status (which creates hassle, but lets them continue their work); or you make them wait until one of the top 10 explicitly logs out. Somtimes the user gets to make the choice. Sometimes it requires an administrator. But that's a policy distinction.
Then you bill them for every time they log in (using the first scheme) or you just enforce the limit (with the second scheme).
I'd recommend a phone home feature, something like alerting you or logging via a web method so you can track who is doing what...but only when they exceed their limit. (research WCF for a couple ways to do this)
That way you could keep track of their usage. Charging them extra or renegotiating their contract becomes meaningful with real data. If you are good at customer service then this shouldn't ruffle their feathers much, especially if you point out that you need an infrastructure for providing service on an elavated user base. Presumably you make it quite clear to them about your licensing scheme too...
The problem with having a table structure of (LogId, UserId, LoginDateTime, LogoutDateTime) is that it becomes difficult to aggregate - queries to see everyone using the system at a specified time are easy, but getting the number of users at all times is hard.
One possible approach would be to denormalise the data a bit - and record units of use, instead of spans. You could track usage in 30 minute blocks with the table structure (UserId, BlockDateTime).
If BettyR used the system from 10:05am until 11:45am, create four records in your table:
BettyR, 10:00am
BettyR, 10:30am
BettyR, 11:00am
BettyR, 11:30am
You can then use a normal SQL query with a group by clause to find the number of distinct users who made use of the system during each half hour period.
select ...
from UsageBlocks
group by BlockDateTime
having count(*) > 10
Depending on your requirements, you could then perform deeper analysis on those specific time periods using a reporting application.