My site allows users to post items for sale. Each item has an expiration date and time, at which point I plan on marking it as expired and removed from the view. Right now, the client has a helper function that determines the time remaining, and marks it as expired once time remaining reaches 0. The issue with this is that the item still appears on the user's view until they have reloaded the page.
I have considered running a cron job to mark expired items, but was concerned this may be too costly as it would have to run very often to be an efficient method.
Is there a more efficient way to handle this? I was hoping to get each item reactively remove itself from the list once the time expires.
I had a similar requirement in an app. I ended up using the remcoder:chronos package to make time reactive. This removed the need for an expiration key as well as any crown jobs. I used reactive time in my Collection.find() query which was returning the cursor of documents to display. At the expiration time they disappear automatically.
Related
Is it necessary to use the Save data as transactions Technic if a value only increases?. In the example Firebase doc social blogging app the starCount can go upp or down so it´s logical to use the Transaction Technic right. But if value only increases I suppose the Transaction Technic is not needed right? or?
Multiple users at the same time increasing a value right.
Edit: 17th, Aug 2021
Now it's also possible to solve this problem without the use of a transaction. We can simply increment a value using:
rootRef.child("score").setValue(ServerValue.increment(1));
And for decremenet, the following line of code is required:
rootRef.child("score").setValue(ServerValue.increment(-1));
The counter can grow up or down, which means that a user can click on the counter to increase the value, but can also decrease the value if he clicks again. When we use transactions, we don't use only to increase or decrease a counter, we use if know that in our app is a possibility that two users can make the same action at the same time. If we don't use transactions, the counter can be increased/decreased only by one, instead of two times, if two users take the action at the same time.
If we use transactions, both actions will take place in different threads of execution, so there is no way in which a counter can be increased/decreased only once, even both users take the same action at the same time.
In conclusion, use transactions every time you think that is a possibility that two or more users can change the same value in your Firebase database at the same time.
I have an ASP.NET 4 application where I have a list of items and users need to do some work on each item. Since the list can be very long, I want this review process for each item to occur as efficiently as possible. My idea is to have a web page that displays one item, the user does what they need to do, then clicks on a Next Item button. The system automatically picks the next item from the list. So far so good...if only one user needs to do this.
The difficulty is in coming up with a reliable and effective solution for allowing multiple users to work through the list. If a user clicks Next, I don't want the system to bring up the same item that another user is working on.
It's not the end of the world if two users work on the same item (the last to save wins), but it's a waste of time and should be kept to a minimum.
Some techniques that I can think of:
1) Pick the next item randomly from the list. The chance of two users getting the same item goes way down. The bad is that users can't predict what they will get next and can't really work sequentially through the list.
2) Use some kind of optimistic locking to lock the record. This is generally bad for web applications since the user can go to any page or kill the connection, potentially leaving the lock there until some kind of expiration. The good part about this is that users can work through the list or parts of it sequentially and the system will simply skip records that somebody else is working on.
However, does anybody have any other suggestins?
Update:
Assuming that a user is only allowed to edit ONE record at a time (i.e. no opening other browser pages or sessions on the same list) one possible solution for using optimistic locking is as follows:
For each record, (as #Shai suggested) keep track of: Edit status (Available, InProgress), User currently editing, Date edit was started.
When a user wants to get the next record, lock the table, scan for the next Available record, change it's status to InProgress, unlock the table. Update the user and date information.
When a session expires (perhaps the user closed their browser), set any records associated with this user to Available. Sessions last a few hours in order to support extended editing timeframe.
If the same user logs on again before the other session is expired, again set any records associated to this user to Available.
Now, this is where it gets a bit complicated. What if the user goes home but didn't finish with a record (or a list of records, if we allow more than one), how do we get other users to be able to take over without waiting? We could add a special UI to list all current user sessions and allow somebody (who knows the user is no longer working) to explicitly unlock any records.
Any suggestions on improving this?
It seems that the items should potentially have 3 statuses (statusi?): Open, InProgress and Completed. When the user requests an item you return the first item with a status of Open, and at the same time set that item's status to "InProgress". And when they save the item, you can set it's status to "Completed". Rinse. Repeat.
To make sure that no two users get the same open item, you can lock the table during a quick sproc that selects the open item and set's its status to "InProgress". This sproc can have the item id as it's return value. By only returning the id rather than the entire record, you will be locking the table for a shorter amount of time. Then you can select the actual record without worrying about another user retrieving ownership of the same record.
You might also want to consider recording the user who took ownership of the item. This might come in handy if you ever need to perform auditing.
Is this the direction you were going for?
I have a situation in which I select an account and I want to bring back its details. This is a single UpdatePanel round trip and its quite quick.
In addition, I need to bring back some transactional information which is from a much bigger table and takes a couple of seconds for the query to come back.
Ideally, I would like to put this into a second update panel and update this additional information once it has been received, but after the first update panel has updated i.e. the user sees:
Change account
See account details (almost instant)
See transactional info (2 seconds later)
The only way I can think of doing this is to use javascript to cause a SECOND postback once the account details have been retrieved to get the transaction information. Is there a better way?
You cannot run two asynchronous postbacks using UpdatePanels at once.
(Otherwise, the ViewState would get messed up)
However, you can make two "raw" AJAX requests (without UpdatePanels) at once, if you're willing to process the results yourself.
I have a requirement that my site always display the number of users currently online. For example, "35741 Users Currently Online". This is not based on a log in, simply how many users are currently on my site. I have tried using Session Start/Session End for this, however session end is not reliable. Therefore I get inflated numbers, as my session start adds numbers but session end doesn't remove them because it doesn't fire.
There is no additional information to be gathered from this (reporting, etc), it's simply requested that the number show up. Very simple request that's turning into a huge deal. Any help is appreciated.
EDIT:
I should specify that I have also tried using a database for this. Simple table that contains a session ID and a last activity column. With each page hit, I check to see if the session is in my database. If not, insert. If so, update with activity time. Then I run a procedure that sweeps the database looking for sessions with no activity in the last 20 minutes. This approach seemed to kill my SQL server and/or IIS. Had to restart the site.
Best way is like you do, but time it out via activity. If a given session doesn't access a page within 5 minutes or so, you may consider them no longer active.
If you're using ASP.Net membership, take a look at GetNumberOfUsersOnline.
For every user action that you can record, you need to consider them "online" for a certain window of time. Depending on the site, you may set that to 5 minutes. The actual web request should take less than a second. You have to make some assumption about how long they might stay on that page and do nothing but be considered online.
This approach requires that you keep track of the time of each users last activity.
Use Performance Counters:
State Server Sessions Active: The
number of active user sessions.
Expanding what silky said in his answer - since really http is stateless to determine if the user is currently 'online' you can really only track how long since the user last accessed your site and make a determination on how long between requests your consider to still be active.
Since you stated that this isn't based upon users logging in may it's a simple of how many different IP addresses you received requests from in the past 5 minutes (or however long you consider the 'online' timeout to be).
Don't use sessions for this unless you also need sessions for something else; it's overkill otherwise.
Assuming a single-server installation, do something like this:
For each user, issue a cookie that contains a unique ID
Maintain a static table of unique IDs and their last access time
In an HttpModule (or Global.asax), enter new users into the table and update their access times (use appropriate locking to prevent race conditions)
Periodically, either from a background thread or in-line with a user request, remove entries from the table that haven't made a request within the last N minutes. You might also want to support an explicit "log out" feature.
Report the number of people online as the size of the table
If you do use sessions, you can use the Session ID as the unique identifier. However, keep in mind that Session IDs aren't issued until you store something in the Session dictionary, unless you have a Session_Start() event configured.
In a load balanced or web garden scenario, it gets a little more complicated, but you can use the same basic idea, just persisting the info in a database instead of in memory.
When the user logs in write his user name into the HttpContext.Current.Cache with a sliding expiration (say 20 minutes).
Then in the Global.asax.cs in the Application_PreRequestHandlerExecute "touch" the cache entry for the current users so it resets the sliding expiration.
When a user explicitly logs out, remove his username from HttpContext.Current.Cache.
If you do this, at any given time HttpContext.Current.Cache.Count will give you the # of current users.
Note: this is assuming you aren't using the Cache for other purposes.
I have a web application at work that is similar to a ticket working system. Some users enter new issues. Other workers choose and resolve issues. All of the data is maintained in MS SQL server 2005.
The users working to resolve issues go to a page where they can view open issues. Because up to twenty people can be looking at this page at the same time, one potential problem I had to address was what happens if someone picks an issue that someone else picked just after their page loaded.
To address this, I did two things. First, the gridview displaying the issues to select uses an AJAX timer to update every second. Once an issue has been selected, it disappears one second later at most. In case they select one within this second, they get a message asking them to choose another.
The problem is that the AJAX part of this is sending too many updates (this is what I am assuming) and it is affecting the performance of the page and database. In addition, the updates are not performing every second. I find the timer to be unreliable when working to trigger stored procedures.
There has to be a better way, but I can't seem to find one. Does anyone have experience with a situation like this or have suggestions to keep multiple users from selecting the same record to maintain? I really do not want to disable the AJAX part entirely because I feel the message alone would make the application frustrating to use.
Thanks,
Put a lock timestamp field on the row in the database. Write a stored proc that returns true or false if the expiration timsetamp is older than a specific time. Set your sessions on your web app to expire in the same time, a minute or two. When a user select a row they hit the stored proc which helps the app to decide if it should let the user to modify it.
Hope that makes sense....
Two things can help mitigate your problem.
First, after-selection notification that the case has been taken is needed regardless of your ajax update time frame. Even checking every second doesn't mean two people cannot click the same case at what they perceive to be the same time. In such cases, one of the users needs to be notified that their selection is invalid even though it appeared valid when selected. This notification doesn't need to be elaborate; keeping a light, helpful tone can improve user perception even in the light of disappointment. And if you identify the user who selected that record already, that will not only help your users coordinate in future but also divert attention from your program to the user who snaked the juicy case. (indeed, management may like giving your users the occasional collision as it will motivate them to select cases faster)
Second, a small tweak to how you display your cases can reduce selection collisions. Adding a random element to display order and/or filtering out every other case on display will help your users select different cases naturally. Human pattern recognition and task selection isn't really random so small changes to presentation can equal big changes to selection behavior. Reductions in collision chance keeps your collision notifications rare (and thus less frustrating to your users). This is even better if your users can be separated into classifications that can help determine useful case ordering/filtering.
Okay, a third thing that will help you over time is if you keep a log of when collisions occur (with helpful meta data about the collision—like who was involved and selection timing). Armed with solid collision data, you can find what works and what doesn't. Over time, you can hone your application to your actual use cases as well as identify potential problems early. Nothing reassures your users more than being on top of a problem (and able to explain your plans to solve it) before they're even aware it exists.
With these mitigating patterns, you'll probably find you can safely reduce your ajax query timeframe without affecting user experience. And with useful logging, you'll have the assurance that any tweaks you put in place are actually working (or not—which is maybe even more useful to know).
I did something similar where once a user opened a ticket (row) it assigned that ticket to that user and set a value on that record, like and FK to that particular user, so if anyone else tried to open that ticket (row) it would let them know it has already been assigned to someone else.
If possible limit the system so that they just get the next open issue off the work queue as opposed having them be able choose from all open issues.
If that isn't possible, I suppose you could check upon the choosing of an issue to see if it is still available. If it's not available, then make it disappear after the user clicks on it. This way you are only requesting when they actually click on something as opposed to constant polling of the data.
Have you tried increasing the time between refreshes. I would expect that once per 30 seconds would be sufficient. 40 requests/minute is a lot less load than 1200/minute. Your users may not even notice the difference.
If they do, how about providing a refresh button on the page so the users can manually refresh the list just prior to selecting an item to avoid the annoying message if they choose.
I'm missing to see the issue, specially after you mentioned you are already flagging tickets as in progress/being maintained and have a timestamp/version of the item.
Isn't the following enough:
User browses the tickets and sees a list of available tickets i.e. this excludes ones that are in the db as in progress. If you want the users to also see tickets in progress, you indicate it clearly in the ticket status and disable the option to take it.
User either flags a ticket as in progress explicitly or implicitly by opening the ticket (depends on the user experience / how its presented to the users).
User explicitly moves the ticket to a different status i.e. completed, invalid, awaiting for feedback, etc.
When the items are retrieved at 1, you include a timestamp/version. When 2 happens, you use a optimistic concurrency approach to make sure that if 2 persons try to update the take the ticket at the same time only the first one will be successful.
What will happen is that for the second person, the update ... where ... timestamp = #timestamp will not find any records to update and you will report back that the ticket was already taken.
If you want, you can build on top of the above to update the UI as tickets are grabbed. This could be by just doing a full refresh of the current page of tickets after x time (maybe alerting/prompting the user), or even by retrieving a list of tickets changed for the page of tickets being showed with ajax. You still have the earlier steps in place, as this modification its just a convenience for the users.