https://www.endpointdev.com/blog/tags/heroku/2016-01-12T00:00:00+00:00End Point DevInstall WordPress on Heroku in OS X Yosemitehttps://www.endpointdev.com/blog/2016/01/install-wordpress-on-heroku-in-os-x/2016-01-12T00:00:00+00:00Marina Lohova
<p>I wanted to install WordPress locally for my blog (about programming!), but using MAMP, XAMP or even Vagrant for this seemed overkill. I wanted a light setup. PHP and Apache are already integrated into Mac OS X, so why not use them? I wanted to deploy the app to Heroku, so that was another thing, since Heroku only provides PostgreSQL, not MySQL, out of the box. I’d like to share my research on how I did it.</p>
<h3 id="wordpress-with-heroku-support">WordPress with Heroku support</h3>
<p>I found <a href="https://github.com/mhoofman/wordpress-heroku">this handy WordPress template with built-in Heroku support</a>. It has everything one needs to run WordPress on Heroku: PostgreSQL for WordPress (because MySQL on Heroku is a paid service), Amazon S3 and Cloudfront for your uploads since Heroku has an ephemeral file system, WP Sendgrid to send emails and WordPress HTTPS. Check out a copy with this command:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">git clone https://github.com/mhoofman/wordpress-heroku.git
</code></pre></div><p>Let’s run the project locally first because a file cannot be written to Heroku’s file system, and updating and installing plugins or themes should be done locally anyways and then pushed to Heroku. I’m using <a href="https://www.jetbrains.com/phpstorm/">PhpStorm</a> for my PHP development.</p>
<h3 id="configuring-apache">Configuring Apache</h3>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">mkdir -p ~/Sites
<span style="color:#038">echo</span> <span style="color:#d20;background-color:#fff0f0">"<html><body><h1>my site works</h1></body></html>"</span> > ~/sites/index.html.en
</code></pre></div><p>Enable PHP support:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">sudo vi /etc/apache2/httpd.conf
</code></pre></div><p>Uncomment the following lines to look like this:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plain" data-lang="plain">LoadModule php5_module libexec/apache2/libphp5.so
LoadModule userdir_module libexec/apache2/mod_userdir.so
Include /private/etc/apache2/extra/httpd-userdir.conf
</code></pre></div><p>Save and exit. Open the following file:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">sudo vi /etc/apache2/extra/httpd-userdir.conf
</code></pre></div><p>Uncomment the following line to look like this:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plain" data-lang="plain">Include /private/etc/apache2/users/*.conf
</code></pre></div><p>Save and exit. Open or create:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">sudo vi /etc/apache2/users/~YOURUSERNAME.conf
</code></pre></div><p>Type the following in there:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plain" data-lang="plain"><Directory "/Users/~YOURUSERNAME/Sites/">
AddLanguage en .en
LanguagePriority en fr de
ForceLanguagePriority Fallback
Options Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from localhost
Require all granted
</Directory>
</code></pre></div><p>Restart Apache with:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">sudo apachectl restart
</code></pre></div><p>Go to http://localhost/~YOURUSER/wordpress-heroku/ and enjoy the results of your work! OK, not so fast! There are more steps to make it happen ;)</p>
<h3 id="enabling-postgresql-for-php">Enabling PostgreSQL for PHP</h3>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plain" data-lang="plain">Your PHP installation appears to be missing the PostgreSQL extension which is required by WordPress with PG4WP.
</code></pre></div><p>Here is a handy script to fix this problem <a href="https://gist.github.com/marinalohova/ec5d77ffd9d8e8acce2c">Install PHP PGSQL extensions on Mac OS X Yosemite (change PHP_VER with your PHP version)</a>.</p>
<h3 id="creating-the-database">Creating the database</h3>
<p>Hit http://localhost/~YOURUSER/blog-heroku/wp-admin/install.php</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">Error establishing a database connection
</code></pre></div><p>The template we are using is tailored for the deployment to Heroku, which means wp-config.php takes its values from the DATABASE_URL environment variable that Heroku config creates in local environment pointing to the database source on Heroku servers.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start
> createdb wordpress
> psql wordpress
CREATE USER wordpress WITH PASSWORD <span style="color:#d20;background-color:#fff0f0">'wordpress'</span>;
GRANT ALL PRIVILEGES ON DATABASE wordpress to wordpress;
</code></pre></div><p>In wp-config.php, edit as follows. Make sure it matches the database and user that you just created.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-php" data-lang="php"><span style="color:#369">$db</span> = parse_url(<span style="color:#369">$_ENV</span>[<span style="color:#d20;background-color:#fff0f0">"DATABASE_URL"</span>] ? <span style="color:#369">$_ENV</span>[<span style="color:#d20;background-color:#fff0f0">"DATABASE_URL"</span>] : <span style="color:#d20;background-color:#fff0f0">"postgres://wordpress:wordpress@localhost:5432/wordpress"</span>);
</code></pre></div><p>Now 5 hours later, you are completely ready for the famous 5-min install ;D. Go to http://localhost/~YOURUSER/blog-heroku/wp-admin/install.php</p>
<h3 id="uploading-the-custom-themeplugin">Uploading the custom theme/plugin</h3>
<p>What to do next? Of course, upload a custom theme or plugin.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plain" data-lang="plain">Unable to create directory wp-content/uploads/2015/08. Is its parent directory writable by the server?
$ cd ~/Sites/THESITE
$ sudo chown -R _www wordpress
$ sudo chmod -R g+w wordpress
</code></pre></div><p>If you encounter an error asking you for FTP credentials in order to do this:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plain" data-lang="plain">To perform the requested action, WordPress needs to access your web server.
Please enter your FTP credentials to proceed.
If you do not remember your credentials, you should contact your web host.
</code></pre></div><p>The problem is that Apache HTTP Server in Mac OS X runs under the user account _www which belongs to the group _www. To allow WordPress to perform operations with Apache, one way to do this is to change the owner of the wordpress directory and its contents to _www. Keep the group as staff, a group to which your user account belongs and give write permissions to the group.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ <span style="color:#038">cd</span> ~/Sites/THESITE
$ sudo chown -R _www wordpress
$ sudo chmod -R g+w wordpress
</code></pre></div><p>This way, no file nor directory is world-writable.</p>
<p>Remember to commit your plugins/themes because due to the nature of Heroku all of the files will be overwritten there if uncommitted or not in the database, effectively wiping out all of your changes at each server restart if you do them on the server.</p>
<p>I installed this pretty theme for myself called Literatum—just bragging.</p>
<h3 id="deployment-to-heroku">Deployment to Heroku</h3>
<p>One of the most exciting last steps. This will make your blog visible to the world! Commit the changes:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">rm -rf .git
git init
git add .
git commit -m <span style="color:#d20;background-color:#fff0f0">"Initial commit"</span>
</code></pre></div><p>Create Heroku app:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ <span style="color:#038">cd</span> wordpress-heroku
$ heroku create
$ heroku addons:create heroku-postgresql
$ heroku pg:promote HEROKU_POSTGRESQL_INSTANCE
$ heroku addons:create sendgrid:starter
</code></pre></div><p>Your first deployment!</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">git push heroku master
</code></pre></div><p>Go to <a href="http://YOURAPP.herokuapp.com/wp-admin/install.php">http://YOURAPP.herokuapp.com/wp-admin/install.php</a> and run the famous 5-minute setup again, activate all the plugins and the chosen custom theme aaand… You are done!</p>
<p>Hope you will find this write-up useful and it will help you create your blog on the web!</p>
Selectively firing Postgres triggershttps://www.endpointdev.com/blog/2015/07/selectively-firing-postgres-triggers/2015-07-15T00:00:00+00:00Greg Sabino Mullane
<div class="separator" style="clear: both; float:right; text-align: center; padding-left: 3em; padding-bottom: 1em;"><a href="/blog/2015/07/selectively-firing-postgres-triggers/image-0-big.jpeg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="/blog/2015/07/selectively-firing-postgres-triggers/image-0.jpeg"/></a><br/><small><a href="https://flic.kr/p/fnSBJW">Lake Wallaga</a> by <a href="https://www.flickr.com/people/tonyheywardimages/">Tony Heyward</a></small></div>
<p>Being able to disable Postgres triggers selectively can be an important skill when doing tasks like bulk updates, in which you only want a subset of the triggers on the table
to be fired. Read below for the long explanation, but the <a href="https://en.wikipedia.org/wiki/TL;DR">TL;DR version</a> of the best solution is to set a WHEN clause on the trigger you wish to skip, making it conditional on a variable such as <strong>session_replication_role</strong>, or <strong>application_name</strong></p>
<pre tabindex="0"><code>CREATE TRIGGER mytrig AFTER INSERT ON foobar FOR EACH
ROW WHEN (current_setting('session_replication_role') <> 'local') EXECUTE PROCEDURE myfunc();
BEGIN;
SET LOCAL session_replication_role = 'local';
UPDATE foobar SET baz = 123;
COMMIT;
</code></pre><p>I decided to spin up a free <a href="https://www.heroku.com/">Heroku</a>
<a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#hobby-tier">“Hobby Dev” database</a> to illustrate the solutions. Generating a test table was done by using the Pagila project, as it has tables which contain triggers. Heroku gives you a randomly generated user and database name. To install <a href="http://www.postgresql.org/ftp/projects/pgFoundry/dbsamples/pagila/pagila/">the Pagila schema</a>, I did:</p>
<pre tabindex="0"><code>$ export H="postgres://vacnvzatmsnpre:2iCDp-46ldaFxgdIx8HWFeXHM@ec2-34-567-89.compute-1.amazonaws.com:5432/d5q5io7c3alx9t"
$ cd pagila-0.10.1
$ psql $H -q -f pagila-schema.sql
$ psql $H -q -f pagila-data.sql
</code></pre><p>Errors appeared on the import, but they can be safely ignored.
One error was because the Heroku database does not have a user named “postgres”, and the other error was due to the fact that the Heroku user is not a superuser. The data, however, was all intact. The sample data is actually quite funny, as the movie titles were semi auto-generated at some point. For example, seven random movie descriptions:</p>
<ul>
<li>A Brilliant Panorama of a Madman And a Composer who must Succumb a Car in Ancient India</li>
<li>A Touching Documentary of a Madman And a Mad Scientist who must Outrace a Feminist in An Abandoned Mine Shaft</li>
<li>A Lackluster Reflection of a Eskimo And a Wretch who must Find a Fanny Pack in The Canadian Rockies</li>
<li>A Emotional Character Study of a Robot And a A Shark who must Defeat a Technical Writer in A Manhattan Penthouse</li>
<li>A Amazing Yarn of a Hunter And a Butler who must Defeat a Boy in A Jet Boat</li>
<li>A Beautiful Reflection of a Womanizer And a Sumo Wrestler who must Chase a Database Administrator in The Gulf of Mexico</li>
<li>A Awe-Inspiring Reflection of a Waitress And a Squirrel who must Kill a Mad Cow in A Jet Boat</li>
</ul>
<p>The table we want to use for this post is named <strong>“film”</strong>, and comes with two triggers on it,
‘film_fulltext_trigger’, and ‘last_updated’:</p>
<pre tabindex="0"><code>heroku=> \d film
Table "public.film"
Column | Type | Modifiers
----------------------+-----------------------------+---------------------------------
film_id | integer | not null default
nextval('film_film_id_seq'::regclass)
title | character varying(255) | not null
description | text |
release_year | year |
language_id | smallint | not null
original_language_id | smallint |
rental_duration | smallint | not null default 3
rental_rate | numeric(4,2) | not null default 4.99
length | smallint |
replacement_cost | numeric(5,2) | not null default 19.99
rating | mpaa_rating | default 'G'::mpaa_rating
last_update | timestamp without time zone | not null default now()
...
Triggers:
film_fulltext_trigger BEFORE INSERT OR UPDATE ON film FOR EACH ROW EXECUTE
PROCEDURE tsvector_update_trigger('fulltext', 'pg_catalog.english', 'title', 'description')
last_updated BEFORE UPDATE ON film FOR EACH ROW EXECUTE PROCEDURE last_updated()
</code></pre><p>The last_updated trigger calls the last_updated() function, which simply sets the last_update column to
<a href="http://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT">CURRENT_TIMESTAMP</a>, which is often seen as its shorter-to-type form, now(). This is a handy metric to track,
but there are times when you want to make changes and <em>not</em> update this field. A typical
example is some sort of bulk change that does not warrant changing all the rows’ last_update
field. How to accomplish this? We need to ensure that the trigger does not fire when
we do our UPDATE. The way many people are familiar with is to simply disable all triggers on the table. So you would do something like this:</p>
<pre tabindex="0"><code>BEGIN;
ALTER TABLE film DISABLE TRIGGER ALL;
UPDATE film SET rental_duration = 10;
ALTER TABLE film ENABLE TRIGGER ALL;
COMMIT;
</code></pre><p>When using Heroku, you are given a regular user, not a Postgres superuser, so the above will generate an error that looks like this:</p>
<pre tabindex="0"><code>ERROR: permission denied: "RI_ConstraintTrigger_a_88776583" is a system trigger.
</code></pre><p>This is caused by the failure of a normal user to disable the internal triggers Postgres uses to maintain foreign key relationships between tables. So the better way is to simply disable the specific trigger like so:</p>
<pre tabindex="0"><code>BEGIN;
ALTER TABLE film DISABLE TRIGGER last_updated;
UPDATE film SET rental_duration = 10;
ALTER TABLE film ENABLE TRIGGER last_updated;
COMMIT;
</code></pre><p>This works on Heroku, but there are two major problems with the ALTER TABLE solution. First, the ALTER TABLE will take a very heavy lock on the entire table, meaning that nobody else will be able to access the table—even to read it!—until your transaction is complete (although Postgres 9.5 will reduce this lock!). The other problem
with disabling triggers this way is that it is too easy to accidentally leave it in a disabled state (although the check_postgres program has a
<a href="https://bucardo.org/check_postgres/check_postgres.pl.html#disabled_triggers">specific check for this!</a>). Let’s take a
look at the lock, and double check that the trigger has been disabled as well:</p>
<pre tabindex="0"><code>heroku=> SELECT last_update FROM film WHERE film_id = 123;
last_update
----------------------------
2015-06-21 16:38:00.891019
heroku=> BEGIN;
heroku=> ALTER TABLE film DISABLE TRIGGER last_updated;
heroku=> SELECT last_update FROM film WHERE film_id = 123;
heroku=> UPDATE film SET rental_duration = 10;
-- We need the subselect because we share with a gazillion other Heroku databases!
heroku=> select relation::regclass,mode,granted from pg_locks where database =
heroku-> (select oid from pg_database where datname = current_database());
relation | mode | granted
----------+---------------------+---------
pg_locks | AccessShareLock | t
film | RowExclusiveLock | t
film | AccessExclusiveLock | t ## This is a very heavy lock!
## Version 9.5 and up will have a ShareRowExclusive lock only!
heroku=> ALTER TABLE film ENABLE TRIGGER last_updated;
heroku=> COMMIT;
-- This is the same value, because the trigger did not fire when we updated
heroku=> select last_update FROM film WHERE film_id = 123;
last_update
----------------------------
2015-06-21 16:38:00.891019
</code></pre><p>What we really want is to use the
<a href="/blog/2015/01/postgres-sessionreplication-role/">powerful session_replication_role parameter</a> to safely disable the triggers. The problem is that the canonical way to disable triggers, by setting session_replication_role to ‘replica’, will disable ALL triggers and rules, for ALL tables. This is not wanted. In our example, we want to stop the <strong>last_updated</strong> trigger from firing, but also want all the other user triggers to fire, as well as the hidden system triggers that are enforcing foreign key referential integrity.</p>
<p>You can set session_replication_role to one of three values: <strong>origin</strong> (the default), <strong>local</strong>, and <strong>replica</strong>. Setting it to “replica” is commonly used in replication systems such as Bucardo and Slony to prevent all rules and triggers from firing. It can also be used for careful bulk loading. Only triggers explicitly set as “replica triggers” will fire when the session_replication_role is set to ‘replica’. The <strong>local</strong> setting is a little harder to understand, as it does not have a direct mapping to a trigger state, as ‘origin’ and ‘replica’ do. Instead, it can be thought of as an alias to ‘origin’—same functionality, but with a different name. What use is that? Well, you can check the value of session_replication_role and do things differently depending on whether it is ‘origin’ or ‘local’. Thus, it is possible to teach a trigger that it should not fire when session_replication_role is set to ‘local’ (or to fire <em>only</em> when it is set to ‘local’).</p>
<p>Thus, our previous problem of preventing the last_updated trigger from firing can be solved by careful use of
the session_replication_role. We want the trigger to NOT fire when session_replication_role is set to ‘local’. This can be accomplished in two ways: modification of the trigger, or modification of the underlying function. Each has its
strengths and weaknesses. Note that session_replication_role can only be set by a superuser, which means I’ll
be switching from Heroku (which only allows connecting as a non-superuser) to a local Pagila database.</p>
<p>For the modify-the-function route, add a quick block at the top to short-circuit the trigger
if the session_replication_role (srr) is set to ‘local’. An advantage to this method is that all triggers that
invoke this function will be affected. In the pagila database, there are 14 tables that have a trigger that
calls the last_updated function. Another advantage is that the exception to the function firing is
clearly visible in the functions definition itself, and thus easy to spot when you examine the
function. Here is how you would modify the last_updated function to only fire when in ‘local’ srr mode:</p>
<pre tabindex="0"><code>CREATE OR REPLACE FUNCTION public.last_updated()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $bc$
BEGIN
IF current_setting('session_replication_role') = 'local' THEN
RETURN NEW;
END IF;
NEW.last_update = CURRENT_TIMESTAMP;
RETURN NEW;
END
$bc$;
</code></pre><p>To invoke it, we change session_replication_role (temporarily!) to ‘local’, then make our
changes. Observe how the value of last_update does not change when we are in ‘local’ mode:</p>
<pre tabindex="0"><code>pagila=# show session_replication_role \t\g
origin
pagila=# begin;
BEGIN
pagila=# select last_update from film where film_id = 203;
2015-06-21 16:38:00.711411
pagila=# update film set rental_duration = 10 WHERE film_id = 203;
UPDATE 1
pagila=# select last_update from film where film_id = 203;
2015-06-21 16:38:03.543831
pagila=# commit;
COMMIT
pagila=# begin;
BEGIN
pagila=# set LOCAL session_replication_role = 'local';
SET
pagila=# select last_update from film where film_id = 203;
2015-06-21 16:38:03.543831
pagila=# update film set rental_duration = 10 WHERE film_id = 203;
UPDATE 1
pagila=# select last_update from film where film_id = 203;
2015-06-21 16:38:03.543831
pagila=# commit;
COMMIT
pagila=# show session_replication_role;
origin
</code></pre><p>The second method for skipping a trigger by using session_replication_role is to modify the
trigger definition itself, rather than changing the function. This has the advantage of not having
to touch the function at all, and also allows you to see that the trigger has been modified when
doing a <strong>\d</strong> of the table. Using ALTER TRIGGER only allows a rename, so we will need to
drop and recreate the trigger. By adding a WHEN clause to the trigger, we can ensure that
it does NOT fire when session_replication_role is set to ‘local’. The SQL looks like this:</p>
<pre tabindex="0"><code>pagila=# begin;
BEGIN
pagila=# drop trigger last_updated ON film;
DROP TRIGGER
pagila=# create trigger last_updated before update on film for each row
pagila-# when (current_setting('session_replication_role') <> 'local') execute procedure last_updated();
CREATE TRIGGER
pagila=# commit;
COMMIT
</code></pre><p>Voila! As before, we can test it out by setting session_replication_role to ‘local’ and confirming that the function does not modify the last_update column. Before doing that, let’s also change the function back to its original form, to keep things honest:</p>
<pre tabindex="0"><code>-- Restore the original version, with no session_replication_role logic:
pagila=# CREATE OR REPLACE FUNCTION public.last_updated() RETURNS TRIGGER LANGUAGE plpgsql
AS $bc$ BEGIN NEW.last_update = CURRENT_TIMESTAMP; RETURN NEW; END $bc$;
CREATE FUNCTION
-- Normal update will change the last_update column:
pagila=# select last_update from film where film_id = 203;
last_update
----------------------------
2015-06-21 16:38:00.121011
pagila=# update film set rental_duration = 10 WHERE film_id = 203;
UPDATE 1
pagila=# select last_update from film where film_id = 203;
last_update
----------------------------
2015-06-21 16:38:03.011004
pagila=# begin;
pagila=# set LOCAL session_replication_role = 'local';
SET
pagila=# update film set rental_duration = 10 WHERE film_id = 203;
UPDATE 1
pagila=# select last_update from film where film_id = 203;
last_update
----------------------------
2015-06-21 16:38:03.011004
-- Show that we are not holding a heavy lock:
pagila=# select relation::regclass,mode,granted from pg_locks where relation::regclass::text = 'film';
relation | mode | granted
----------+------------------+---------
film | AccessShareLock | t
film | RowExclusiveLock | t
pagila=# commit;
COMMIT
</code></pre><p>Those are the three main ways to selectively disable a trigger on a table: using ALTER TABLE to completely disable it (and invoking a heavy lock), having the function check session_replication_role (affects all triggers using it, requires superuser), and having the trigger use a WHEN clause (requires superuser). Sharp readers may note that being a superuser is not really required, as something other than session_replication_role could be used. Thus, a solution is to use a parameter that can be changed by anyone, that will not affect anything else, and can be set to a unique value. Here is one such solution, using the handy “application_name” parameter. We will return to the Heroku database for this one:</p>
<pre tabindex="0"><code>heroku=> drop trigger last_updated on film;
heroku=> create trigger last_updated before update on film for each row
when (current_setting('application_name') <> 'skiptrig') execute procedure last_updated();
heroku=> select last_update from film where film_id = 111;
2015-06-21 16:38:00.365103
heroku=> update film set rental_duration = 10 WHERE film_id = 111;
UPDATE 1
heroku=> select last_update from film where film_id = 111;
2015-06-21 16:38:03.101115
heroku=> begin;
BEGIN
heroku=> set LOCAL application_name = 'skiptrig';
SET
heroku=> update film set rental_duration = 10 WHERE film_id = 111;
UPDATE 1
heroku=> select last_update from film where film_id = 111;
2015-06-21 16:38:03.101115
-- Show that we are not holding a heavy lock:
heroku=> select relation::regclass,mode,granted from pg_locks where database =
heroku-> (select oid from pg_database where datname = current_database());
relation | mode | granted
----------+------------------+---------
film | AccessShareLock | t
film | RowExclusiveLock | t
heroku=> commit;
COMMIT
</code></pre><p>So there you have it: four solutions to the problem of skipping a single trigger. Which to use depends on your circumstances. I prefer the WHEN + session_replication_role option, as it forces you to be a superuser, and is very visible when looking at the trigger via \d.</p>
Heroku: dumping production database to staginghttps://www.endpointdev.com/blog/2015/06/heroku-dumping-production-database-to/2015-06-17T00:00:00+00:00Marina Lohova
<p>If you need to dump the production database locally Heroku has a nice set of tools to make this as smooth as humanly possible. In short, remember these two magic words: pg:pull and pg:push. This article details the process <a href="https://devcenter.heroku.com/articles/heroku-postgresql#pg-push-and-pg-pull">https://devcenter.heroku.com/articles/heroku-postgresql#pg-push-and-pg-pull</a></p>
<p>However, when I first tried it I had to resolved few issues.</p>
<p>My first problem was:</p>
<pre tabindex="0"><code>pg:pull not found
</code></pre><p>To fix this:</p>
<ol>
<li>Uninstall the “heroku” gem with</li>
</ol>
<pre tabindex="0"><code>gem uninstall heroku (Select 'All Versions')
</code></pre><ol start="2">
<li>Find your Ruby “bin” path by running</li>
</ol>
<pre tabindex="0"><code>gem env
</code></pre><p>(it’s under “EXECUTABLE DIRECTORY:”)</p>
<ol start="3">
<li>
<p>Cd to the “bin” folder.</p>
</li>
<li>
<p>Remove the Heroku executable with</p>
</li>
</ol>
<pre tabindex="0"><code>rm heroku
</code></pre><ol start="5">
<li>
<p>Restart your shell (close Terminal tab and re-open)</p>
</li>
<li>
<p>Type</p>
</li>
</ol>
<pre tabindex="0"><code>heroku version
</code></pre><p>you should now see something like:</p>
<pre tabindex="0"><code>heroku-toolbelt/2.33.1 (x86_64-darwin10.8.0) ruby/1.9.3
</code></pre><p>Now you can proceed with the transfer:</p>
<ol>
<li>Type</li>
</ol>
<pre tabindex="0"><code>heroku config --app production-app
</code></pre><p>Note the DATABASE_URL, for example let’s imagine that the production database url is HEROKU_POSTGRESQL_KANYE_URL, and the staging database url is HEROKU_POSTGRESQL_NORTH</p>
<ol start="2">
<li>Run</li>
</ol>
<pre tabindex="0"><code>heroku pg:pull HEROKU_POSTGRESQL_KANYE rtwtransferdb --app production-app
heroku config --app staging-app
heroku pg:push rtwtransferdb HEROKU_POSTGRESQL_NORTH --app rtwtest
</code></pre><p>This is when I hit the second problem:</p>
<pre tabindex="0"><code>database is not empty
</code></pre><p>I fixed it by doing:</p>
<pre tabindex="0"><code>heroku pg:reset HEROKU_POSTGRESQL_NORTH
</code></pre><p>Happy database dumping!</p>
Little Spree Big Performance Problemshttps://www.endpointdev.com/blog/2013/08/little-spree-big-performance-problems/2013-08-05T00:00:00+00:00Marina Lohova
<p>Recently I worked on an online food store serving an area with very little infrastructure. As a result, the orders tended to be really big with lots of products.</p>
<p>The website worked in the following environment:</p>
<ul>
<li>Ruby 1.9.2</li>
<li>Spree 0.60</li>
<li>Heroku, Bamboo stack</li>
<li>PostgreSQL 9.2.4</li>
</ul>
<h3 id="h12-timeout-errors">H12 timeout errors</h3>
<p>The performance problems started when we migrated Bamboo to Cedar on Heroku and replaced Thin webserver with Unicorn. We started getting a lot of <a href="https://devcenter.heroku.com/articles/request-timeout">Heroku Request timeout errors - H12</a>:</p>
<img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-0.png"/>
<p>The problems happened mostly when logging in to admin dashboard or during the checkout for the certain orders. H12 errors occur when a HTTP request takes longer than 30 seconds to complete. For example, if a Rails app takes 35 seconds to render the page, the HTTP router returns a 503 after 30 seconds and abandons the incomplete Rails request for good. The Rails request will keep working and logging the normal errorless execution. After completion, the request will indefinitely hang in the application dyno.</p>
<p>We started debugging H12: we set Unicorn timeout to 20 seconds to prevent the runaway requests and installed the rack-timeout gem with the timeout of 10 seconds to raise an error on a slow request. It all came down to a trivial database timeout!</p>
<img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-1.png"/>
<p>The application source has not changed during the transition from Bamboo to Cedar, but apparently Cedar/Unicorn is much more sensitive to the troubled code. Below is the list of performance bottlenecks and solutions in Spree. Some of them exist in version 0.60 only, but a lot of them are still present in Spree 1.x, which means that your application may have them too.</p>
<h3 id="issue-1-real-time-reports">Issue #1: Real-time reports</h3>
<p>Let’s take a closer look at the earlier database timeout code. It came from Admin Dashboard and admin/overview_controller.rb.</p>
<img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-2.png"/>
<p>The “Best Selling variants" report was being calculated real-time right in the web process:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#080;font-weight:bold">def</span> <span style="color:#06b;font-weight:bold">best_selling_variants</span>
li = <span style="color:#036;font-weight:bold">LineItem</span>.includes(<span style="color:#a60;background-color:#fff0f0">:order</span>).
where(<span style="color:#d20;background-color:#fff0f0">"orders.state = 'complete'"</span>).
sum(<span style="color:#a60;background-color:#fff0f0">:quantity</span>, <span style="color:#a60;background-color:#fff0f0">:group</span> => <span style="color:#a60;background-color:#fff0f0">:variant_id</span>, <span style="color:#a60;background-color:#fff0f0">:limit</span> => <span style="color:#00d;font-weight:bold">5</span>)
...
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><p>Record counts in the database are large enough to crash the application on Heroku with the database timeout:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">irb(main):<span style="color:#00d;font-weight:bold">001</span>:<span style="color:#00d;font-weight:bold">0</span>> <span style="color:#036;font-weight:bold">LineItem</span>.count
=> <span style="color:#00d;font-weight:bold">162279</span>
irb(main):<span style="color:#00d;font-weight:bold">002</span>:<span style="color:#00d;font-weight:bold">0</span>> <span style="color:#036;font-weight:bold">Order</span>.count
=> <span style="color:#00d;font-weight:bold">13027</span>
irb(main):<span style="color:#00d;font-weight:bold">003</span>:<span style="color:#00d;font-weight:bold">0</span>> <span style="color:#036;font-weight:bold">Variant</span>.count
=> <span style="color:#00d;font-weight:bold">14418</span>
</code></pre></div><p>Other reports on the Dashboard experience the same problem. They would cause the timeout in turns when logging into Admin:</p>
<ul>
<li>top_grossing_variants</li>
<li>best_selling_taxons</li>
<li>last_five_orders</li>
<li>biggest_spenders</li>
</ul>
<h3 id="solution">Solution</h3>
<p>Fortunately, in Spree 1.x the internal reporting system has been replaced with <a href="https://web.archive.org/web/20130807090154/http://jirafe.com:80/">Jirafe</a>:</p>
<img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-3.png"/>
<p>If switching to Spree 1.x is not an option, another way is to move the calculation into a background job, using, for example, delayed_job gem and Heroku Scheduler Addon:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">task <span style="color:#a60;background-color:#fff0f0">:statistics</span> => <span style="color:#a60;background-color:#fff0f0">:environment</span> <span style="color:#080;font-weight:bold">do</span>
<span style="color:#036;font-weight:bold">Delayed</span>::<span style="color:#036;font-weight:bold">Job</span>.enqueue <span style="color:#036;font-weight:bold">StatisticsJob</span>.new
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><h3 id="issue-2-large-numbers">Issue #2: Large numbers</h3>
<div class="separator" style="clear: both"><img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-4.jpeg" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;" /></div>
<p>It is an established fact that humans eat a lot! Think about an order of a thousand Heineken 6-pack cans…</p>
<p>Or even something like this:</p>
<div class="separator" style="clear: both"><img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-5.png"/></div>
<p>or this:</p>
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-6.jpeg"/></div>
<p>Spree, both 0.60 and 1.x, proved to have a huge problem if an order has a lot of line items and/or a large quantity of single line items. The potentially dangerous code can be found all over the place. Consider the following example:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#080;font-weight:bold">class</span> <span style="color:#b06;font-weight:bold">InventoryUnit</span> < <span style="color:#036;font-weight:bold">ActiveRecord</span>::<span style="color:#036;font-weight:bold">Base</span>
<span style="color:#080;font-weight:bold">def</span> <span style="color:#b06;font-weight:bold">self</span>.<span style="color:#06b;font-weight:bold">destroy_units</span>(order, variant, quantity)
variant_units = order.inventory_units.group_by(&<span style="color:#a60;background-color:#fff0f0">:variant_id</span>)[variant.id].sort_by(&<span style="color:#a60;background-color:#fff0f0">:state</span>)
quantity.ceil.times <span style="color:#080;font-weight:bold">do</span>
inventory_unit = variant_units.shift
inventory_unit.destroy
<span style="color:#080;font-weight:bold">end</span>
<span style="color:#080;font-weight:bold">end</span>
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><p>Now imagine what will happen with the order from the first screenshot. We have 15100 inventory units for that one. They will be meticulously destroyed from the inventory one by one in a loop after the checkout. This method was born to crash the application!</p>
<h3 id="solution-1">Solution</h3>
<p>A simple mindful refactoring was enough to solve the problem for me. There is no need to call “destroy” in the loop for every single inventory unit because we can use the efficient “destroy_all” method. I’m sure this can be optimized further, but it was enough to get rid of the timeout:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#080;font-weight:bold">def</span> <span style="color:#b06;font-weight:bold">self</span>.<span style="color:#06b;font-weight:bold">destroy_units</span>(order, variant, quantity)
variant_units = order.inventory_units.
group_by(&<span style="color:#a60;background-color:#fff0f0">:variant_id</span>)[variant.id].
sort_by(&<span style="color:#a60;background-color:#fff0f0">:state</span>)
variant_units = variant_units.shift(quantity.ceil)
<span style="color:#036;font-weight:bold">InventoryUnit</span>.
where(<span style="color:#a60;background-color:#fff0f0">:order_id</span> => order.id,<span style="color:#a60;background-color:#fff0f0">:variant_id</span> => variant.id).
order(<span style="color:#d20;background-color:#fff0f0">'state asc'</span>).limit(quantity.ceil).
destroy_all
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><h3 id="issue-3-real-time-emails">Issue #3: Real-time emails</h3>
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-4.jpeg" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;" /></div>
<p>All emails in Spree are sent in real-time.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#080;font-weight:bold">class</span> <span style="color:#b06;font-weight:bold">Order</span> < <span style="color:#036;font-weight:bold">ActiveRecord</span>::<span style="color:#036;font-weight:bold">Base</span>
<span style="color:#080;font-weight:bold">def</span> <span style="color:#06b;font-weight:bold">finalize!</span>
...
<span style="color:#036;font-weight:bold">OrderMailer</span>.confirm_email(<span style="color:#038">self</span>).deliver
...
<span style="color:#080;font-weight:bold">end</span>
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><p>Why is it bad? Let’s look at the following example from my application:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#080;font-weight:bold">def</span> <span style="color:#06b;font-weight:bold">confirm_email</span>(order)
attachments[<span style="color:#d20;background-color:#fff0f0">"invoice.pdf"</span>] = {
<span style="color:#d20;background-color:#fff0f0">'Content-type'</span> => <span style="color:#d20;background-color:#fff0f0">'application/pdf'</span>,
<span style="color:#a60;background-color:#fff0f0">:content</span> => <span style="color:#036;font-weight:bold">OrderInvoice</span>.new.to_pdf(order)}
mail(<span style="color:#a60;background-color:#fff0f0">:subject</span> => <span style="color:#d20;background-color:#fff0f0">'Order #'</span> + order.number,
<span style="color:#a60;background-color:#fff0f0">:from</span> => <span style="color:#036;font-weight:bold">Spree</span>::<span style="color:#036;font-weight:bold">Config</span>[<span style="color:#a60;background-color:#fff0f0">:order_from</span>],
<span style="color:#a60;background-color:#fff0f0">:to</span> => order.email)
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><p>In my application “confirm_email” was overridden and generated the PDF invoice. The invoice listed all the products in the order and had about 200 lines in it. Again, it lead to the H12 timeout error.</p>
<h3 id="solution-2">Solution</h3>
<p>All emails should be sent in the background rather than in the web request. First, because network operations can take a long time, and second, because generating an email can also be slow. For example, sending in the background can be accomplished using <a href="https://github.com/collectiveidea/delayed_job">delayed_job gem</a>:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#036;font-weight:bold">OrderMailer</span>.delay.confirm_email(<span style="color:#038">self</span>)
</code></pre></div><h3 id="issue-4-lazy-loading">Issue #4: Lazy-loading</h3>
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-4.jpeg" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;" /></div>
<p>Ecommerce objects are usually complicated with a lot of associations. This is totally fine as long as you eager-load the associations that will be used most with the loaded object later on. In most cases, Spree does not preload associations for its orders. For example, in spree/base_controller.rb:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#33b">@order</span> = <span style="color:#036;font-weight:bold">Order</span>.find_by_number! params[<span style="color:#a60;background-color:#fff0f0">:order_id</span>]
</code></pre></div><p>As the result, here is what I see in server console while loading the order display page on the frontend:</p>
<div class="separator" style="clear: both"><img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-9.png"/></div>
<p>…And five more screens like this! The associations of the order — line items, variants and products — generate an additional chain of queries to the database during lazy-loading.</p>
<h3 id="solution-eager-loading">Solution: Eager-loading</h3>
<p>If I modify the line from the controller like this…</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#33b">@order</span> = <span style="color:#036;font-weight:bold">Order</span>.where(<span style="color:#a60;background-color:#fff0f0">:number</span> => params[<span style="color:#a60;background-color:#fff0f0">:order_id</span>])
.includes(<span style="color:#a60;background-color:#fff0f0">:line_items</span> => {<span style="color:#a60;background-color:#fff0f0">:product</span> => <span style="color:#a60;background-color:#fff0f0">:taxons</span>, <span style="color:#a60;background-color:#fff0f0">:variant</span> => [<span style="color:#a60;background-color:#fff0f0">:product</span>, <span style="color:#a60;background-color:#fff0f0">:option_values</span>]})
.includes(<span style="color:#a60;background-color:#fff0f0">:adjustments</span>).first
</code></pre></div><p>…SQL queries will shrink down to this:</p>
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-10.png"/></div>
<p>Eager-loading did the trick. Of course, not everything needs to be loaded eagerly, and the solution varies from case to case. It worked like charm in my case.</p>
<h3 id="issue-5-dangerous-code-all-over-the-place">Issue #5: Dangerous code all over the place</h3>
<div class="separator" style="clear: both; text-align: center;"><img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-4.jpeg" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;" /></div>
<p>There a lot of places in the Spree source code that are not optimized for performance. We don’t need to look far for an example, because there is another killer method right near the “destroy_units” one we inspected earlier!</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#080;font-weight:bold">class</span> <span style="color:#b06;font-weight:bold">InventoryUnit</span> < <span style="color:#036;font-weight:bold">ActiveRecord</span>::<span style="color:#036;font-weight:bold">Base</span>
<span style="color:#080;font-weight:bold">def</span> <span style="color:#b06;font-weight:bold">self</span>.<span style="color:#06b;font-weight:bold">create_units</span>(order, variant, sold, back_order)
shipment = order.shipments.detect {|shipment| !shipment.shipped? }
sold.ceil.times {
order.inventory_units.create(<span style="color:#a60;background-color:#fff0f0">:variant</span> => variant, <span style="color:#a60;background-color:#fff0f0">:state</span> => <span style="color:#d20;background-color:#fff0f0">"sold"</span>, <span style="color:#a60;background-color:#fff0f0">:shipment</span> => shipment)
}
back_order.ceil.times {
order.inventory_units.create(<span style="color:#a60;background-color:#fff0f0">:variant</span> => variant, <span style="color:#a60;background-color:#fff0f0">:state</span> => <span style="color:#d20;background-color:#fff0f0">"backordered"</span>, <span style="color:#a60;background-color:#fff0f0">:shipment</span> => shipment)
}
<span style="color:#080;font-weight:bold">end</span>
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><p>And then:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">order.line_items.each <span style="color:#080;font-weight:bold">do</span> |line_item|
back_order = determine_backorder(order, variant, quantity)
sold = quantity - back_order
create_units(order, line_item.variant, sold, back_order)
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><p>I received a timeout either in the “sold” or the “backorder” loop, but there wasn’t a time when I didn’t receive a timeout!</p>
<h3 id="solution-3">Solution</h3>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#080;font-weight:bold">def</span> <span style="color:#b06;font-weight:bold">self</span>.<span style="color:#06b;font-weight:bold">create_units</span>(order, variant, sold, back_order)
shipment = order.shipments.detect {|shipment| !shipment.shipped? }
values = sold.ceil.times.to_a.map { <span style="color:#d20;background-color:#fff0f0">"(</span><span style="color:#33b;background-color:#fff0f0">#{</span>order.id<span style="color:#33b;background-color:#fff0f0">}</span><span style="color:#d20;background-color:#fff0f0">,</span><span style="color:#33b;background-color:#fff0f0">#{</span>variant.id<span style="color:#33b;background-color:#fff0f0">}</span><span style="color:#d20;background-color:#fff0f0">,'sold',</span><span style="color:#33b;background-color:#fff0f0">#{</span>shipment.id<span style="color:#33b;background-color:#fff0f0">}</span><span style="color:#d20;background-color:#fff0f0">)"</span> } +
back_order.ceil.times.to_a.map { <span style="color:#d20;background-color:#fff0f0">"(</span><span style="color:#33b;background-color:#fff0f0">#{</span>order.id<span style="color:#33b;background-color:#fff0f0">}</span><span style="color:#d20;background-color:#fff0f0">,</span><span style="color:#33b;background-color:#fff0f0">#{</span>variant.id<span style="color:#33b;background-color:#fff0f0">}</span><span style="color:#d20;background-color:#fff0f0">,'backordered',</span><span style="color:#33b;background-color:#fff0f0">#{</span>shipment.id<span style="color:#33b;background-color:#fff0f0">}</span><span style="color:#d20;background-color:#fff0f0">)"</span> }
values.in_groups_of(<span style="color:#00d;font-weight:bold">500</span>, <span style="color:#080">false</span>) <span style="color:#080;font-weight:bold">do</span> |group|
<span style="color:#036;font-weight:bold">InventoryUnit</span>.connection.execute(<span style="color:#d20;background-color:#fff0f0">"INSERT INTO inventory_units(order_id, variant_id, state, shipment_id) VALUES </span><span style="color:#33b;background-color:#fff0f0">#{</span>group.join(<span style="color:#d20;background-color:#fff0f0">','</span>)<span style="color:#33b;background-color:#fff0f0">}</span><span style="color:#d20;background-color:#fff0f0">"</span>)
<span style="color:#080;font-weight:bold">end</span>
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><p>Another example: every line item has the after_create and after_save callbacks. The callback invokes the Order.update! method. Order.update! method calls update_totals method…twice throughout the method.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#080;font-weight:bold">def</span> <span style="color:#06b;font-weight:bold">update_totals</span>
<span style="color:#038">self</span>.payment_total = payments.completed.map(&<span style="color:#a60;background-color:#fff0f0">:amount</span>).sum
<span style="color:#038">self</span>.item_total = line_items.map(&<span style="color:#a60;background-color:#fff0f0">:amount</span>).sum
<span style="color:#038">self</span>.adjustment_total = adjustments.map(&<span style="color:#a60;background-color:#fff0f0">:amount</span>).sum
<span style="color:#038">self</span>.total = item_total + adjustment_total
<span style="color:#080;font-weight:bold">end</span>
</code></pre></div><p>Now imagine the order from the second screenshot with a lot of line items. During the checkout “update_totals” will be called each time the line item is saved. Typically, this line would produce a timeout, because the “line_items” association was, of course, not preloaded:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">line_items.map(&<span style="color:#a60;background-color:#fff0f0">:amount</span>).sum
</code></pre></div><p>I couldn’t list every circumstance like that, because it would require a lot of context to explain the catch, but I can still say many times …</p>
<h3 id="no-long-running-tasks-in-the-web-request">No long-running tasks in the web request!</h3>
<p>Be it Spree, Heroku, or any other context, environment or platform, please, never do the following in the web process:</p>
<div class="separator" style="clear: both"><img border="0" src="/blog/2013/08/little-spree-big-performance-problems/image-12.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" /></div>
<ul>
<li>(!!!) Heavy database usage (slow or numerous queries, N+1 queries)</li>
<li>Sending an email</li>
<li>Accessing a remote API (posting to Twitter, querying Flickr, etc.)</li>
<li>Rendering an image or PDF</li>
<li>Heavy computation (computing a fibonacci sequence, etc.)</li>
</ul>
<p>Say “No” to all these things to ensure a much happier life for your application!</p>