Commit f2731aac authored by Peter Leitzen's avatar Peter Leitzen

Merge branch 'doc-development-application-limits' into 'master'

Application Limits development documentation

Closes #38250

See merge request gitlab-org/gitlab!21949
parents 337e1fe2 dfe9ec2c
......@@ -34,3 +34,11 @@ Read more in the [CI documentation](../ci/yaml/README.md#processing-git-pushes).
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/21164) in GitLab 8.12.
Activity history for projects and individuals' profiles was limited to one year until [GitLab 11.4](https://gitlab.com/gitlab-org/gitlab-foss/issues/52246) when it was extended to two years, and in [GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/issues/33840) to three years.
## Number of project webhooks
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/20730) in GitLab 12.6.
A maximum number of project webhooks applies to each GitLab.com tier. Check the
[Maximum number of webhooks (per tier)](../user/project/integrations/webhooks.md#maximum-number-of-webhooks-per-tier)
section in the Webhooks page.
......@@ -72,6 +72,7 @@ description: 'Learn how to contribute to GitLab.'
- [Mass Inserting Models](mass_insert.md)
- [Cycle Analytics development guide](cycle_analytics.md)
- [Issue types vs first-class types](issue_types.md)
- [Application limits](application_limits.md)
## Performance guides
......
# Application limits development
This document provides a development guide for contributors to add application
limits to GitLab.
## Documentation
First of all, you have to gather information and decide which are the different
limits that will be set for the different GitLab tiers. You also need to
coordinate with others to [document](../administration/instance_limits.md)
and communicate those limits.
There is a guide about [introducing application
limits](https://about.gitlab.com/handbook/product/#introducing-application-limits).
## Development
The merge request to [configure maximum number of webhooks per
project](https://gitlab.com/gitlab-org/gitlab/merge_requests/20730/diffs) is a
good example about configuring application limits.
### Insert database plan limits
In the `plan_limits` table, you have to create a new column and insert the
limit values. It's recommended to create separate migration script files.
1. Add new column to the `plan_limits` table with non-null default value 0, eg:
```ruby
add_column(:plan_limits, :project_hooks, :integer, default: 0, null: false)
```
NOTE: **Note:** Plan limits entries set to `0` mean that limits are not
enabled.
1. Insert plan limits values into the database using
`create_or_update_plan_limit` migration helper, eg:
```ruby
create_or_update_plan_limit('project_hooks', 'free', 10)
create_or_update_plan_limit('project_hooks', 'bronze', 20)
create_or_update_plan_limit('project_hooks', 'silver', 30)
create_or_update_plan_limit('project_hooks', 'gold', 100)
```
### Plan limits validation
#### Get current limit
Access to the current limit can be done through the project or the namespace,
eg:
```ruby
project.actual_limits.project_hooks
```
#### Check current limit
There is one method `PlanLimits#exceeded?` to check if the current limit is
being exceeded. You can use either an `ActiveRecord` object or an `Integer`.
Ensures that the count of the records does not exceed the defined limit, eg:
```ruby
project.actual_limits.exceeded?(:project_hooks, ProjectHook.where(project: project))
```
Ensures that the number does not exceed the defined limit, eg:
```ruby
project.actual_limits.exceeded?(:project_hooks, 10)
```
#### `Limitable` concern
The [`Limitable` concern](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/app/models/concerns/ee/limitable.rb)
can be used to validate that a model does not exceed the limits. It ensures
that the count of the records for the current model does not exceed the defined
limit.
NOTE: **Note:** The name (pluralized) of the plan limit introduced in the
database (`project_hooks`) must correspond to the name of the model we are
validating (`ProjectHook`).
```ruby
class ProjectHook
include Limitable
end
```
......@@ -3,12 +3,16 @@
class PlanLimits < ApplicationRecord
belongs_to :plan
def exceeded?(limit_name, relation)
def exceeded?(limit_name, object)
return false unless enabled?(limit_name)
# relation.count >= limit value is slower than checking
# if a record exists at the limit value - 1 position.
relation.limit(1).offset(read_attribute(limit_name) - 1).exists?
if object.is_a?(Integer)
object >= read_attribute(limit_name)
else
# object.count >= limit value is slower than checking
# if a record exists at the limit value - 1 position.
object.limit(1).offset(read_attribute(limit_name) - 1).exists?
end
end
private
......
# frozen_string_literal: true
require 'spec_helper'
describe PlanLimits do
let(:plan_limits) { create(:plan_limits) }
let(:model) { ProjectHook }
let(:count) { model.count }
before do
create(:project_hook)
end
context 'without plan limits configured' do
describe '#exceeded?' do
it 'does not exceed any relation offset' do
expect(plan_limits.exceeded?(:project_hooks, model)).to be false
expect(plan_limits.exceeded?(:project_hooks, count)).to be false
end
end
end
context 'with plan limits configured' do
before do
plan_limits.update!(project_hooks: 2)
end
describe '#exceeded?' do
it 'does not exceed the relation offset' do
expect(plan_limits.exceeded?(:project_hooks, model)).to be false
expect(plan_limits.exceeded?(:project_hooks, count)).to be false
end
end
context 'with boundary values' do
before do
create(:project_hook)
end
describe '#exceeded?' do
it 'does exceed the relation offset' do
expect(plan_limits.exceeded?(:project_hooks, model)).to be true
expect(plan_limits.exceeded?(:project_hooks, count)).to be true
end
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment