Developer:Activity Limits

From myExperiment

Jump to: navigation, search

Activity Limits

By Sergejs Aleksejevs, 2nd December 2008    /    Last updated on 5th December 2008


Contents


The Need for Activity Limits

At the current stage of the lifecycle of myExperiment, the developer team has made a decision that certain user activities need to be limited, especially for newly registered users. This is required to ensure reliable operation of the website for legitimate users and also to restrict scope / coverage of potentially malicious actions - e.g. spamming. Other use cases might include the need to limit certain actions to enforce fair distribution of server resources to all users.


Counters

All the limitations over user actions are implemented with the help of counters. The model in place is very flexible and allows for many various types of activity limits. Please see the diagram below:

Image:Counter_Hierarchy.png


Counter Types

  • Non-periodic counters provide "absolute" limitations over certain actions. These span over duration of the lifecycle of the user account on myExperiment.
    • the counter will never be reset;
    • no promotions - the limit will never get increased by the system;
    • quota can only be extended / counter reset by system administrators;
    • example use case: to limit total volume of data that the user can upload on myExperiment - total size of all user workflows, files, packs, pictures, etc.


  • Periodic counters will have their counter reset over time wth a certain frequency (independent for all individual counters). This allows for introducing the notion of "user allowance" for different features in a defined timeframe.
    • counter will only be reset when the user accesses a feature;
    • example use case: daily limit on the number of internal messages that the user is allowed to send;


  • Counters with promotions
    • provide a dynamic allowance model - user allowance for some features can increase over time;
    • can only be set up for periodic counters;
    • promotions happen only at the time of counter reset (which works well, because counter reset period is most likely to be much shorter than promotion period); this also ensures that if the user starts using a feature then suddenly stops, the limit for the feature will not keep increasing (resulting in, for example, thousands of allowed daily messages) - hence, only the user that actively accesses some feature will get frequent promotions;
    • two types of counters with promotions: one-time promotions (can make instant increase of allowance to the absolute maximum value for the feature OR can turn the feature into unlimited one), multiple promotions (can increase the limit infinitely over time OR can do promotions with small limit increments until user allowance reaches the absolute maximum limit for the particular feature, at which point further promotions stop);
    • example use case: when the user first joins myExperiment their daily limit for messages is relatively small; over time the users become "trusted", meaning that their daily allowance can be increased (or the counter can be turned into an absolute one by system administrators - thus disabling the feature for malicious users);


How It Works

At the moment myExperiment doesn't have any background processes - therefore, it's impossible to reset periodic counters at the exact point in time (e.g. every day at midnight).

Hence, there is a need for event-driven system. The obvious thing would be to reset all expired counters for users at the time when they sign in. This, however, is impossible, because sessions are in use to improve user experiences, meaning that there can be extended periods when explicit "signing in" event for a particular user will not happen. Instead, the decision was to perform all the required counter operations directly before the user is authorized to perform the desired action.

When the user first accesses a feature, a new counter for this feature for the current user is created - its settings (like reset frequency, limit value, etc) are obtained from /config/environment_private.rb. On subsequent accesses of the feature a check is made if the counter exists (new one created if not), and if counter reset / limit increase ("promotion") is required at this time. A check is made if the limit is not exceeded (counter incremented, if required) and result returned to the controller - which, in turn, shows the feature view or displays an error message.


Implementation Details

  • All counter are held in "activity_limits" database table.
  • To prevent cases when the user would, for example, type in the whole internal message and then learn that it can't be sent because they have already reached their daily allowance, there is a need for double checking the counters: at the time the user acesses the feature (but before the action of that feature is executer - hence this is like a "test" run, which checks the counter, but won't increment it) and at the time when the user actually executes the action.


Feautures that are already limited

  • internal messages
  • inviting people to myExperiment (by email) / making external friend requests (by email)
  • inviting people to groups on myExperiment (by email)


Settings for Activity Limits

Each feature that needs to be limited will require a set of 5 settings, these are described below.

 Note: First part of every setting is the name of the feature being limited.
  • <feature_name>_LIMIT_START_VALUE - the initial maximum allowance for the feature (used when the new limit is created)
  • <feature_name>_LIMIT_MAX_VALUE - absolute maximum allowance for the feature (this can't be exceeded after any promotions);
NULL for always increasing allowance
  • <feature_name>_LIMIT_FREQUENCY -- in hours -- the time period over which the allowance is given; for example 5 messages (allowance) for 24 hours (frequency)
NULL for non-periodic limits (i.e. limits which won't have their counters reset every <frequency> hours)
  • <feature_name>_LIMIT_PROMOTE_EVERY -- in days -- every <X> days the user will be promoted to the new level,
where the allowance per frequency period will be adjusted by <feature_name>_LIMIT_PROMOTE_INCREMENT;
NULL to indicate that promotion should never happen
  • <feature_name>_LIMIT_PROMOTE_INCREMENT - should be positive;
0 to indicate that promotion shouldn't expand the allowance (why would this be useful?)
NULL to perform a one-time promotion by setting the limit to whatever the value of <feature_name>_LIMIT_MAX_VALUE is;
NULL when the <feature_name>_LIMIT_MAX_VALUE is also NULL makes the feature unlimited.


Database Record Structure

Each DB record for feature limit contains:

  • contributor (e.g. user or group that is limited)
 t.column :contributor_type, :string, :null => false
 t.column :contributor_id, :integer, :null => false
  • which action for the contributor is limited
 t.column :limit_feature, :string, :null => false
  • "limit_max" - maximum number of times (NULL for unlimited) the action can be executed over
"limit_frequency" period (in hours); "limit_frequency" set to NULL means that the limit is not periodic
 t.column :limit_max, :integer
 t.column :limit_frequency, :integer
  • number of times the action has already been executed since the last reset (governed by "limit_frequency")
(can't be NULL - doesn't make sense to have NULL value for the counter)
 t.column :current_count, :integer, :null => false
  • date/time after which "current_count" is to be reset to "limit_max" (for periodic limits - such as daily message limit)
(NULL to indicate that reset should never happen and the limit is absolute, i.e. non-periodic)
(the code will assume that if either --or both-- of "limit_frequency" and "reset_after" are NULLs, the limit is non-periodic)
 t.column :reset_after, :datetime
  • date/time after which promotion to the next level (with, probably, higher "limit_max" should happen)
(NULL to indicate that promotion should never happen and the user is to stay at the same level)
 t.column :promote_after, :datetime
Personal tools