Skip to content

Commit 68e3f52

Browse files
committed
Basic Heroku integration
1 parent 8e6a8ea commit 68e3f52

File tree

9 files changed

+221
-10
lines changed

9 files changed

+221
-10
lines changed

.env.sample

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
RAILS_ENV=development

.gitignore

+5-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ sublime-project.sublime-workspace
5050
*.swp
5151
*.swo
5252

53-
# don't check in multisite config
53+
# don't check in multisite config
5454
config/multisite.yml
5555
# don't check in my renamed multisite config as well :)
5656
config/multisite1.yml
@@ -69,5 +69,8 @@ chef/tmp/*
6969
# .procfile
7070
.procfile
7171

72-
# exclude our git version file for now
72+
# .env, local environment variables for use with foreman
73+
.env
74+
75+
# exclude our git version file for now
7376
config/version.rb

config/initializers/04-message_bus.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
end
1717

1818
# Point at our redis
19-
MessageBus.redis_config = YAML::load(File.open("#{Rails.root}/config/redis.yml"))[Rails.env].symbolize_keys
19+
MessageBus.redis_config = YAML.load(ERB.new(File.new("#{Rails.root}/config/redis.yml").read).result)[Rails.env].symbolize_keys
2020

2121
MessageBus.long_polling_enabled = SiteSetting.enable_long_polling
2222
MessageBus.long_polling_interval = SiteSetting.long_polling_interval

config/initializers/mini_profiler.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# If Mini Profiler is included via gem
22
if defined?(Rack::MiniProfiler)
33

4-
Rack::MiniProfiler.config.storage_options = YAML::load(File.open("#{Rails.root}/config/redis.yml"))[Rails.env].symbolize_keys
4+
Rack::MiniProfiler.config.storage_options = YAML.load(ERB.new(File.new("#{Rails.root}/config/redis.yml").read).result)[Rails.env].symbolize_keys
55
Rack::MiniProfiler.config.storage = Rack::MiniProfiler::RedisStore
66

77
# For our app, let's just show mini profiler always, polling is chatty so nuke that

config/redis.yml.sample

+11-1
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,21 @@ profile:
1111
<<: *defaults
1212

1313
test:
14-
<<: *defaults
14+
<<: *defaults
1515
db: 1
1616

1717
staging:
1818
<<: *defaults
1919

2020
production:
2121
<<: *defaults
22+
23+
# Example for using environment variables
24+
#
25+
# production:
26+
# uri: <%= uri = URI.parse(ENV['OPENREDIS_URL']) if ENV['OPENREDIS_URL'] %>
27+
# host: <%= uri.host if uri %>
28+
# port: <%= uri.port if uri %>
29+
# password: <%= uri.password if uri %>
30+
# db: 0
31+
# cache_db: 2

docs/HEROKU.md

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Basic Heroku deployment
2+
3+
This guide takes you through the steps for deploying Discourse to the [Heroku](http://www.heroku.com/) cloud application platform. If you're unfamiliar with Heroku, [read this first](https://devcenter.heroku.com/articles/quickstart). The basic deployment of Discourse requires several services that will cost you money. In addition to the [750 free Dyno hours](https://devcenter.heroku.com/articles/usage-and-billing) provided by Heroku, the application requires one additional process to be running for the Sidekiq queue ($34 monthly), and a Redis database plan that supports a minimum of 2 databases (average $10 monthly).
4+
5+
For details on how to reduce the monthly cost of your application, see the Advanced Heroku deployment instructions (coming soon).
6+
7+
## Download and configure Discourse
8+
9+
1. If you haven't already, download Discourse and create a new branch for your Heroku configuration.
10+
11+
git clone [email protected]:discourse/discourse.git
12+
cd discourse
13+
git checkout -b heroku
14+
15+
2. Modify `production:` in the redis.yml file to use environment variables provided by Heroku and the Redis provider of your choice.
16+
17+
*config/redis.yml*
18+
19+
...
20+
21+
production:
22+
uri: <%= uri = URI.parse(ENV['OPENREDIS_URL']) if ENV['OPENREDIS_URL'] %>
23+
host: <%= uri.host if uri %>
24+
port: <%= uri.port if uri %>
25+
password: <%= uri.password if uri %>
26+
db: 0
27+
cache_db: 2
28+
29+
3. Comment out or delete `config/redis.yml` from .gitignore. We want to include redis.yml when we push to Heroku.
30+
31+
*.gitignore*
32+
33+
- config/redis.yml
34+
+ # config/redis.yml
35+
36+
4. Commit your changes.
37+
38+
git add .
39+
git commit -m "ready for Heroku"
40+
41+
42+
## Configure Heroku
43+
44+
1. Create the heroku app. This automatically creates a git remote called heroku.
45+
46+
heroku create your-app-name
47+
48+
2. Add a suitable Redis provider from [Heroku add-ons](https://addons.heroku.com/), (this service will cost you money).
49+
50+
heroku addons:add openredis:micro
51+
52+
3. Add the [Heroku Scheduler](https://addons.heroku.com/scheduler) add-on, this saves us from running a separate clock process, reducing the cost of the app.
53+
54+
heroku addons:add scheduler:standard
55+
56+
4. Generate a secret token in the terminal.
57+
58+
rake secret
59+
60+
5. Push the secret to the stored heroku environment variables, this will now be available to your app globally.
61+
62+
heroku config:add SECRET_TOKEN=<generated secret>
63+
64+
##### The next step is optional, as it is still in experimental 'labs' status with Heroku. You can choose to precompile your assets locally before deployment instead. If you do choose to precompile locally, remember to do it each time, before you deploy. For more information on this experimental feature see [Heroku Labs: user-env-compile](https://devcenter.heroku.com/articles/labs-user-env-compile).
65+
66+
6. Make the environment variables available to heroku during deployment.
67+
68+
heroku labs:enable user-env-compile -a your-app-name
69+
70+
**Caveat:** If you should need to change or add environment variables for any reason, you will need to remove `user-env-compile`, then re-apply it after making the changes. This will then require you to make a commit, even if it is an empty commit, and then push to Heroku for the changes to be applied.
71+
72+
If needed, you can remove the user-env-compile option with this command.
73+
74+
heroku labs:disable user-env-compile -a your-app-name
75+
76+
7. Push your heroku branch to Heroku.
77+
78+
git push heroku heroku:master
79+
80+
8. Migrate and seed the database.
81+
82+
heroku run rake db:migrate db:seed_fu
83+
84+
##### You should now be able to visit your app at http://`<your-app-name>`.herokuapp.com
85+
86+
## Configure the deployed application
87+
88+
1. Log into the app, using your preferred auth provider.
89+
90+
2. Connect to the Heroku console to make the first user an Admin.
91+
92+
heroku run console
93+
94+
3. Enter the following commands.
95+
96+
u = User.first
97+
u.admin = true
98+
u.approved = true
99+
u.save
100+
101+
4. Provision the Heroku Scheduler
102+
103+
This will allow Heroku Scheduler to cue up tasks rather than running a separate clock process.
104+
In the [Heroku dashboard](https://dashboard.heroku.com/apps), select your app, then click on **Heroku Scheduler Standard** under your Add-ons.
105+
106+
Next, add a Job for each of the following:
107+
108+
##### TASK: `rake enqueue_digest_emails` FREQUENCY: `Daily` NEXT RUN: `06:00`
109+
110+
##### TASK: `rake category_stats` FREQUENCY: `Daily` NEXT RUN: `04:00`
111+
112+
##### TASK: `rake calculate_avg_time` FREQUENCY: `Every 10 minutes`
113+
114+
##### TASK: `rake feature_topics` FREQUENCY: `Every 10 minutes`
115+
116+
##### TASK: `rake calculate_score` FREQUENCY: `Every 10 minutes`
117+
118+
##### TASK: `rake calculate_view_counts` FREQUENCY: `Every 10 minutes`
119+
120+
##### TASK: `rake version_check` FREQUENCY: `Daily` NEXT RUN: `01:00`
121+
122+
5. Start Sidekiq
123+
124+
In the [Heroku dashboard](https://dashboard.heroku.com/apps), select your app and you will see the separate processes that have been created for your application under Resources. You will only need to start the sidekiq process for your application to run properly. The clock process is covered by Heroku Scheduler, and you can even remove this from the Procfile before deploying if you so wish. The worker process has been generated as a Rails default and can be ignored. As you can see **the Sidekiq process costs $34 monthly** to run. If you want to reduce this cost, check out the Advanced Heroku deployment(coming soon).
125+
126+
Click on the check-box next to the Sidekiq process and click Apply Changes
127+
128+
##### Your Discourse application should now be functional. However, you will still need to configure mail functionality and file storage for uploaded images. For some recommendations on doing this within Heroku, see the Advanced Heroku deployment guide (coming soon).
129+
130+
## Running the application locally
131+
132+
Using Foreman to start the application allows you to mimic the way the application is started on Heroku. It loads environment variables via the .env file and instantiates the application using the Procfile. In the .env sample file, we have set `RAILS_ENV='development'`, this makes the Rails environment variable available globally, and is required when starting this application using Foreman.
133+
134+
##### Create the .env file
135+
136+
*.env*
137+
138+
RAILS_ENV='development'
139+
140+
141+
142+
###Foreman commands:
143+
144+
145+
##### Create the database
146+
147+
bundle exec foreman run rake db:create
148+
149+
##### Migrate and seed the database
150+
151+
bundle exec foreman run rake db:migrate db:seed_fu
152+
153+
##### Start the application using Foreman
154+
155+
bundle exec foreman start
156+
157+
##### Use Rails console, with pry
158+
159+
bundle exec foreman run rails console

lib/discourse_redis.rb

+5-4
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
class DiscourseRedis
55

66
def initialize
7-
@config = YAML::load(File.open("#{Rails.root}/config/redis.yml"))[Rails.env]
7+
@config = YAML.load(ERB.new(File.new("#{Rails.root}/config/redis.yml").read).result)[Rails.env]
88
redis_opts = {:host => @config['host'], :port => @config['port'], :db => @config['db']}
9+
redis_opts[:password] = @config['password'] if @config['password']
910
@redis = Redis.new(redis_opts)
1011
end
1112

@@ -36,14 +37,14 @@ def self.namespace
3637
end
3738

3839
def self.new_redis_store
39-
redis_config = YAML::load(File.open("#{Rails.root}/config/redis.yml"))[Rails.env]
40-
redis_store = ActiveSupport::Cache::RedisStore.new "redis://#{redis_config['host']}:#{redis_config['port']}/#{redis_config['cache_db']}"
40+
redis_config = YAML.load(ERB.new(File.new("#{Rails.root}/config/redis.yml").read).result)[Rails.env]
41+
redis_store = ActiveSupport::Cache::RedisStore.new "redis://#{(':' + redis_config['password'] + '@') if redis_config['password']}#{redis_config['host']}:#{redis_config['port']}/#{redis_config['cache_db']}"
4142
redis_store.options[:namespace] = -> { DiscourseRedis.namespace }
4243
redis_store
4344
end
4445

4546
def url
46-
"redis://#{@config['host']}:#{@config['port']}/#{@config['db']}"
47+
"redis://#{(':' + @config['password'] + '@') if @config['password']}#{@config['host']}:#{@config['port']}/#{@config['db']}"
4748
end
4849

4950
end

lib/tasks/scheduler.rake

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
desc "This task is called by the Heroku scheduler add-on"
2+
3+
# Every day at 6am
4+
task :enqueue_digest_emails => :environment do
5+
Jobs::EnqueueDigestEmails.new.execute(nil)
6+
end
7+
8+
# Every day at 4am
9+
task :category_stats => :environment do
10+
Jobs::CategoryStats.new.execute(nil)
11+
end
12+
13+
# Every 10 minutes
14+
task :calculate_avg_time => :environment do
15+
Jobs::CalculateAvgTime.new.execute(nil)
16+
end
17+
18+
# Every 10 minutes
19+
task :feature_topics => :environment do
20+
Jobs::FeatureTopics.new.execute(nil)
21+
end
22+
23+
# Every 10 minutes
24+
task :calculate_score => :environment do
25+
Jobs::CalculateScore.new.execute(nil)
26+
end
27+
28+
# Every 10 minutes
29+
task :calculate_view_counts => :environment do
30+
Jobs::CalculateViewCounts.new.execute(nil)
31+
end
32+
33+
# Every day
34+
task :version_check => :environment do
35+
Jobs::VersionCheck.new.execute(nil)
36+
end

vendor/gems/rails_multisite/lib/rails_multisite/connection_management.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ def self.config_filename
5656
end
5757

5858
def self.current_hostname
59-
ActiveRecord::Base.connection_pool.spec.config[:host_names].first
59+
config = ActiveRecord::Base.connection_pool.spec.config
60+
config[:host_names].nil? ? config[:host] : config[:host_names].first
6061
end
6162

6263

0 commit comments

Comments
 (0)