<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <id>tag:devcenter.heroku.com,2005:/articles/feed</id>
  <link rel="alternate" type="text/html" href="http://devcenter.heroku.com" />
  
  <title>Heroku Dev Center Articles</title>
  <author>
    <name>Heroku</name>
  </author>
  <updated>2013-05-23T23:45:33Z</updated>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/herokudevcenterarticles" /><feedburner:info uri="herokudevcenterarticles" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <id>tag:devcenter.heroku.com,2005:Article/1605</id>
    <published>2013-05-23T23:45:33Z</published>
    <updated>2013-05-23T23:45:33Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/qaRZwZYHI0w/process-scheduler" />
    <title>Process Scheduler</title>
    <content type="html">&lt;p&gt;&lt;a href="http://addons.heroku.com/process-scheduler"&gt;Process Scheduler&lt;/a&gt; is an &lt;a href="http://addons.heroku.com"&gt;add-on&lt;/a&gt; that allows for easy scheduling of Heroku processes depending on the hour of the day and day of the week.&lt;/p&gt;&lt;p&gt;Configuring Process Scheduler to scale your processes of any kind is done in a few clicks through a calendar web UI and will allow you to save on dyno hours with very minimal efforts.&lt;/p&gt;&lt;img src="https://s3.amazonaws.com/heroku.devcenter/heroku_assets/images/150-original.jpg?1363885247" title="Process Scheduler dashboard" width="500px"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;Provisioning the add-on&lt;/h2&gt;&lt;p&gt;Process Scheduler can be attached to a Heroku application via the  CLI:&lt;/p&gt;&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:add process-scheduler
-----&amp;gt; Adding process-scheduler to sharp-mountain-4005... done, v18 (free)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After installing Process Scheduler, it should be configured to properly scale your processes.&lt;/p&gt;&lt;h2&gt;Service setup&lt;/h2&gt;&lt;p&gt;The Process Scheduler dashboard allows you to configure the schedule for each of the process types of your application.&lt;/p&gt;&lt;p&gt;The dashboard can be accessed via the CLI:&lt;/p&gt;&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:open process-scheduler
Opening process-scheduler for sharp-mountain-4005…
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;or by visiting the &lt;a href="http://heroku.com/myapps"&gt;Heroku apps web interface&lt;/a&gt; and selecting the application in question. Select Process Scheduler from the Add-ons menu.&lt;/p&gt;&lt;p&gt;The first time you visit the Process Scheduler dashboard, you will need to fill in your Heroku API key and your time zone before configuring your processes schedules.&lt;/p&gt;&lt;h2&gt;Removing the add-on&lt;/h2&gt;&lt;p&gt;Process Scheduler can be removed via the  CLI.&lt;/p&gt;&lt;div class="warning"&gt;This will destroy all associated data and cannot be undone!&lt;/div&gt;&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:remove process-scheduler
-----&amp;gt; Removing process-scheduler from sharp-mountain-4005... done, v20 (free)
&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Support&lt;/h2&gt;&lt;p&gt;All Process Scheduler support and runtime issues should be submitted via one of the &lt;a href="https://devcenter.heroku.com/support-channels"&gt;Heroku Support channels&lt;/a&gt;. Any non-support related issues or product feedback is welcome at the &lt;a href="http://processscheduler.uservoice.com"&gt;Process Scheduler UserVoice&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/qaRZwZYHI0w" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/process-scheduler</feedburner:origLink></entry>
  <entry>
    <id>tag:devcenter.heroku.com,2005:Article/1299</id>
    <published>2013-05-23T23:45:31Z</published>
    <updated>2013-05-23T23:45:31Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/yuRpgyaEu24/rcmmndr" />
    <title>Rcmmndr</title>
    <content type="html">&lt;p&gt;Rcmmndr (http://addons.heroku.com/rcmmndr) is a recommendation engine &lt;a href="http://addons.heroku.com"&gt;add-on&lt;/a&gt; based on Apache Mahout.&lt;/p&gt;

&lt;p&gt;Adding a recommendation engine to an application will enable the application’s users to discover items or other people they might not have found by themselves. Providing similar functionality with hard-coded search algorithms may be difficult once the application gets bigger and complex.&lt;/p&gt;

&lt;p&gt;Rcmmndr is a collaborative filtering solution, which essentially means that, it will take all the current preferences that have been made in your application, and try to guess new preferences for a specific user. It is not specific to item types, but it only depends on the present preferences data. You can recommend books, movies, cars to your users, or even other users to follow.&lt;/p&gt;

&lt;p&gt;Rcmmndr is easily accessible via a REST API and has supported thin client libraries for Java, Ruby and Python.&lt;/p&gt;

&lt;p&gt;You can refer to the &lt;a href="https://cwiki.apache.org/confluence/display/MAHOUT/Mahout+Wiki"&gt;Official Mahout documentation&lt;/a&gt; or “Mahout In Action” book if you would like to get extensive information on how the recommendations are done. But to summarize; Rcmmndr will take all the preferences that you have created and calculate a user similarity based on these preferences, which then will be used to make recommendations to the users. Sometimes there might not be enough information to make recommendations for a specific user, at this case the server will return an empty json body.&lt;/p&gt;

&lt;p&gt;Rcmmndr is using a sensible-default recommendation algorithm,so it is ready to make recommendations as soon as you put your data in. But you can also customize the recommender and tune it better for your domain.&lt;/p&gt;

&lt;h2 id="provisioning-the-addon"&gt;Provisioning the add-on&lt;/h2&gt;

&lt;p&gt;Rcmmndr can be attached to a Heroku application via the CLI:&lt;/p&gt;
&lt;div class="callout"&gt;
&lt;p&gt;A list of all plans available can be found&lt;/p&gt;
&lt;a href="http://addons.heroku.com/rcmmndr"&gt;
&lt;p&gt;here&lt;/p&gt;
&lt;/a&gt;
&lt;p&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:add rcmmndr
-----&amp;gt; Adding rcmmndr to sharp-mountain-4005... done, v18 (free)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once RCMMNDR has been added a &lt;code&gt;RCMMNDR_ACCESS_URL&lt;/code&gt; setting will be available in the app configuration and will contain the canonical URL used to access the newly provisioned RCMMNDR service instance. This can be confirmed using the &lt;code&gt;heroku config:get&lt;/code&gt; command.&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku config:get RCMMNDR_ACCESS_URL
http://api.rcmmndr.com/api_key/{your_api_key}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After installing Rcmmndr the application should be configured to fully integrate with the add-on.&lt;/p&gt;

&lt;h2 id="api-reference"&gt;API Reference&lt;/h2&gt;

&lt;p&gt;This is the general api reference that you can refer to see how the web service is implemented.&lt;/p&gt;

&lt;h3 id="preference-api"&gt;Preference API&lt;/h3&gt;

&lt;p&gt;You can do the crud operations about preferences using this api. Please refer to bulk api for batch operations.&lt;/p&gt;

&lt;p&gt;Rcmmndr is a colloborative filtering service. The flow starts with creating preferences. A single preference contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;user_id&lt;/strong&gt; : the actual user on your app that made the preference&lt;/li&gt;
	&lt;li&gt;
&lt;strong&gt;item_id&lt;/strong&gt; : the item that the user expressed the preference for, such as a book or a movie&lt;/li&gt;
	&lt;li&gt;
&lt;strong&gt;rating&lt;/strong&gt;: the level of the preference if applicable.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;So for instance, if you own an ecommerce website and you want to create a recommendation widget based on your sales, you might want to set a default value to the rating field which is the same for all users. But if you have a rating value as well you can use it.&lt;/p&gt;

&lt;h4 id="creating-a-preference"&gt;Creating a preference&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;api_key/{apiKey}/preference/{uid}/{iid}/{rating}&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl -X POST "http://api.rcmmndr.com/api_key/{API_KEY}/preference/1/101/5"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This command will add a preference for user with id 1 to the item 101 with a weight of 5.&lt;/p&gt;

&lt;h4 id="deleting-preferences-with-specific-user-id"&gt;Deleting preferences with specific user id&lt;/h4&gt;

&lt;p&gt;To delete all the preferences that belong to a specific user id:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl -X DELETE "http://api.rcmmndr.com/api_key/{API_KEY}/preference/{uid}"&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id="deleting-all-preferences"&gt;Deleting all preferences&lt;/h4&gt;
&lt;p class="warning"&gt;This will delete all the preferences that you have created on that account&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -X DELETE "http://api.rcmmndr.com/api_key/{API_KEY}/preference/_all"&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id="exporting-your-preference-data"&gt;Exporting your preference data&lt;/h4&gt;

&lt;p&gt;You can get all your data in csv format like the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl -X GET "http://api.rcmmndr.com/api_key/{API_KEY}/preference/_all"&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="recommendation-api"&gt;Recommendation API&lt;/h3&gt;

&lt;h4 id="get-a-recommendation-for-a-user"&gt;Get a recommendation for a user&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;api_key/{apiKey}/recommend/{uid}&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl -X GET "http://api.rcmmndr.com/api_key/{API_KEY}/recommend/1"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will return the top 10 recommendations for user 1&lt;/p&gt;

&lt;h3 id="bulk-api"&gt;Bulk API&lt;/h3&gt;

&lt;p&gt;Please note that currently,the process of loading a dump file will override your existing data.&lt;/p&gt;

&lt;h4 id="to-load-a-preferences-file-dump"&gt;To load a preferences file dump:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;curl -X POST "http://api.rcmmndr.com/api_key/{API_KEY}/preference/_bulk" --data-binary @preferences.tsv -H "Content-Type: text/plain"&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id="to-load-a-gzip-compressed-preferences-file-dump"&gt;To load a gzip compressed preferences file dump:&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;curl -X POST "http://api.rcmmndr.com/api_key/{API_KEY}/preference/_bulk" --data-binary @preferences.tsv.gz -H "Content-Type: text/plain" -H "Content-Encoding: gzip"&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="stats-api"&gt;Stats API&lt;/h3&gt;

&lt;p&gt;You can use this api to check for your account statistics. Stats API will return the results in json format.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl -X GET "http://api.rcmmndr.com/api_key/{API_KEY}/_stats"&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="settings-api"&gt;Settings API&lt;/h3&gt;

&lt;p&gt;You can use the settings api to finetune your recommender and check how different algorithms behave on your dataset.&lt;/p&gt;

&lt;h4 id="get-current-settings"&gt;Get Current Settings&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;curl -X GET "http://api.rcmmndr.com/api_key/{API_KEY}/_settings"

&amp;gt;&amp;gt;&amp;gt; {"response":"tenant has no customizations"}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you have defined a custom recommender, you will see the definition here. Rcmmndr uses a JSON based DSL to express custom recommenders. If you do not see any customizations such as the case above, it means that you are using the default recommender. (GenericUserBasedRecommender)&lt;/p&gt;

&lt;h4 id="update-settings"&gt;Update Settings&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;curl -X POST "http://api.rcmmndr.com/api_key/{API_KEY}/_settings" -H "Content-Type:application/json" -d '{
         "recommender": {
              "impl":"SlopeOneRecommender"
         }
    }' &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will use the SlopeOneRecommender instead of the default GenericUserBasedRecommender.&lt;/p&gt;

&lt;p&gt;Now if you do a get on the same Rest url, you will see that your settings has been updated:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
	"recommender": {
    	"impl":"SlopeOneRecommender"
	}
}&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id="available-recommenders"&gt;Available Recommenders&lt;/h4&gt;

&lt;p&gt;Different recommender algorithms or same algorithms with different parameters will lead to different recommendations on the same dataset for the same users. You can finetune the system as you wish using the settings DSL. Please remember check the Apache Mahout Documentation for choosing the suitable Recommender.&lt;/p&gt;

&lt;h5 id="using-slopeonerecommender"&gt;Using SlopeOneRecommender&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;{
	"recommender": {
    	"impl":"SlopeOneRecommender"
	}
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can post the descriptor above to switch to SlopeOneRecommender. SlopeOneRecommender does not have any parameters so the DSL is simple. Please check the Apache Mahout Documentation for details about SlopeOneRecommender.&lt;/p&gt;

&lt;h5 id="using-genericuserbasedrecommender"&gt;Using GenericUserBasedRecommender&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;{
"recommender": {
    "impl": "GenericUserBasedRecommender",
    "params": {
        "UserSimilarity": {
            "impl": "PearsonCorrelationSimilarity"
        },
        "UserNeighborhood": {
            "impl": "NearestNUserNeighborhood",
            "params": {
                "n": 2
            }
        }
    }
}
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can post the descriptor above to switch to GenericUserBasedRecommender. &lt;strong&gt;A UserBasedRecommender requires a UserSimilarity and a User Neighborhood.&lt;/strong&gt; Please check the Apache Mahout Documentation for details.&lt;/p&gt;

&lt;h6 id="supported-user-similarity-algorithms"&gt;Supported User Similarity Algorithms&lt;/h6&gt;

&lt;pre&gt;&lt;code&gt;PearsonCorrelationSimilarity
LogLikelihoodSimilarity
TanimotoCoefficientSimilarity
EuclideanDistanceSimilarity&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;are currently supported.Please refer to the Apache Mahout Documentation for details.&lt;/p&gt;

&lt;h6 id="supported-user-neighborhood-algorithms"&gt;Supported User Neighborhood Algorithms&lt;/h6&gt;

&lt;pre&gt;&lt;code&gt;NearestNUserNeighborhood&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;is currently supported. You can change the size of the User Neighborhood with the “n” parameter. N should be between the range 2-50 at the moment.&lt;/p&gt;

&lt;h5 id="genericitembasedrecommender"&gt;GenericItemBasedRecommender&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;{
"recommender": {
    "impl": "GenericItemBasedRecommender",
    "params": {
        "ItemSimilarity": {
            "impl": "PearsonCorrelationSimilarity"
        }
    }
}
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can post the descriptor above to switch to GenericItemBasedRecommender. &lt;strong&gt;An ItemBasedRecommender requires an ItemSimilarity.&lt;/strong&gt; Please check the Apache Mahout Documentation for details.&lt;/p&gt;

&lt;h6 id="supported-item-similarity-algorithms"&gt;Supported Item Similarity Algorithms&lt;/h6&gt;

&lt;pre&gt;&lt;code&gt;PearsonCorrelationSimilarity
LogLikelihoodSimilarity
TanimotoCoefficientSimilarity
EuclideanDistanceSimilarity&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;are currently supported.Please refer to the Apache Mahout Documentation for details.&lt;/p&gt;

&lt;h3 id="estimation-api"&gt;Estimation API&lt;/h3&gt;

&lt;p&gt;You can get an estimation to a user’s specific preference for an item as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl -X GET "http://api.rcmmndr.com/api_key/{API_KEY}/estimate/{user_id}/{item_id}"        	&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="evaluation-api"&gt;Evaluation API&lt;/h3&gt;

&lt;p&gt;While experimenting with these different recommenders, you might want to check which recommender performs better with your domain by evaluating how closely the estimated preferences match the actual preferences.&lt;/p&gt;

&lt;p&gt;For this purpose Mahout provides some built in evaluators, and some of them are currently available in the Evaluation Api.&lt;/p&gt;

&lt;h5 id="supported-evaluators"&gt;Supported Evaluators&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;AverageAbsoluteDifferenceRecommenderEvaluator
RMSRecommenderEvaluator&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can check the details of these evaluators form the Mahout documentation but in short, Root-mean-square (RMSRecommenderEvaluator) more heavily penalizes the estimates that are much different from the expected ones.&lt;/p&gt;

&lt;p&gt;Evaluation is done by spitting the dataset into two, one is used for running the original recommender and the other is used for comparing the results.&lt;/p&gt;

&lt;h5 id="evaluator-parameters"&gt;Evaluator Parameters&lt;/h5&gt;

&lt;p&gt;&lt;strong&gt;trainingPercentage&lt;/strong&gt;: For instance 0.7 means that the evaluator will train with the %70 of the data and test with %30 of the data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;evaluationPercentage&lt;/strong&gt;: 0.1 means that %10 of the data will be used in evaluation process. Note that during the beta, this propery might be limitied to a lower default until the development is finalized.&lt;/p&gt;

&lt;h5 id="averageabsolutedifferencerecommenderevaluator"&gt;AverageAbsoluteDifferenceRecommenderEvaluator&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;{
	"evaluator": {
    	"impl": "AverageAbsoluteDifferenceRecommenderEvaluator",
    	"params": {
        	"trainingPercentage": 0.1,
        	"evaluationPercentage": 0.1
    	}
	}
}&lt;/code&gt;&lt;/pre&gt;

&lt;h5 id="rmsrecommenderevaluator"&gt;RMSRecommenderEvaluator&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;{
	"evaluator": {
    	"impl": "RMSRecommenderEvaluator",
    	"params": {
        	"trainingPercentage": 0.7,
        	"evaluationPercentage": 0.2
    	}
	}
}&lt;/code&gt;&lt;/pre&gt;

&lt;h5 id="sample-usage"&gt;Sample Usage&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;curl --include -X GET http://api.rcmmndr.com/api_key/{API_KEY}/_evaluate -d  '{
"evaluator": {
    "impl": "AverageAbsoluteDifferenceRecommenderEvaluator",
    "params": {
        "trainingPercentage": 0.1,
        "evaluationPercentage": 0.1
    }
}
}' -H "Content-Type:application/json"&lt;/code&gt;&lt;/pre&gt;

&lt;h5 id="assessing-the-result"&gt;Assessing the Result&lt;/h5&gt;

&lt;p&gt;The evaluation result will be a double value similar to the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
	"score": 0.9635416666666665
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the average difference between the estimated preferences and the actual preferences. The result above was extracted from a dataset whose preferences were in the range 1 to 5. So the result means that on average our recommendation is of by 0.9 ,Depending on your requirements you can interpret this in different ways,for our test scenario its does not seem great but not too bad as well. You can try this evaluation with different evaluator and recommender settings.&lt;/p&gt;

&lt;p&gt;A perfect recommendation’s score would be 0. Meaning that there are no differences at all. But this is probably impossible without some domain specific hints to the recommender.&lt;/p&gt;

&lt;h2 id="using-with-ruby-or-rails-3x"&gt;Using with Ruby or Rails 3.x&lt;/h2&gt;

&lt;p&gt;You can use the &lt;a href="https://github.com/Rcmmndr/RubyRcmmndr"&gt;RubyRcmmndr&lt;/a&gt; gem to start making recommendations.&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;gem 'RubyRcmmndr', '0.0.1', :git =&amp;gt; 'https://github.com/Rcmmndr/RubyRcmmndr.git'&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Update application dependencies with bundler.&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ bundle install&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="creating-a-client-instance"&gt;Creating a Client Instance&lt;/h3&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;require 'RubyRcmmndr'
client = RubyRcmmndr::Client.new("API_KEY")&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="adding-preferences"&gt;Adding Preferences&lt;/h3&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;client.create_preference(1,102,2.5)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will add user ‘1’ a preference of ‘2.5’ for the item ‘102’&lt;/p&gt;

&lt;h3 id="making-recommendations"&gt;Making Recommendations&lt;/h3&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;recs=client.get_recommendation(1)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;the Ruby Data Structure ‘recs’ contains the recommendation results as itemid,value pairs&lt;/p&gt;

&lt;h3 id="usage-statistics"&gt;Usage Statistics&lt;/h3&gt;

&lt;p&gt;You can check the usage statistics for your account as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;client.get_usage_stats()["total_preferences"]
client.get_usage_stats()["distinct_keys"]&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="deleting-preferences"&gt;Deleting Preferences&lt;/h3&gt;

&lt;h4 id="deleting-preferences-for-specific-user"&gt;Deleting Preferences for specific user&lt;/h4&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;client.delete_preferences_of_user(1)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will delete all the preferences of user ‘1’&lt;/p&gt;

&lt;h4 id="deleting-all-preferences"&gt;Deleting All Preferences&lt;/h4&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;client.delete_all_preferences&lt;/code&gt;&lt;/pre&gt;
&lt;p class="warning"&gt;This will delete all the data in your account.&lt;/p&gt;
&lt;h3 id="bulk-api"&gt;Bulk API&lt;/h3&gt;

&lt;p&gt;Bulk API is a better way of inserting many number of preference values. It is done by posting a text file (comma or tab separated) to the server.&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;client.bulk_update_preferences("preferences.tsv")&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where the contents of preferences.tsv are similar to the following: (userID,itemID,preference)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;196,242,3
186,302,3
22,377,1
244,51,2
166,346,1&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="using-with-pythondjango"&gt;Using with Python/Django&lt;/h2&gt;

&lt;p&gt;You can use the &lt;a href="https://github.com/Rcmmndr/pyrcmmndr"&gt;PyRcmmndr&lt;/a&gt; module to start making recommendations.&lt;/p&gt;

&lt;h3 id="installation"&gt;Installation&lt;/h3&gt;

&lt;pre&gt;&lt;code class="term"&gt;pip install git+https://github.com/Rcmmndr/pyrcmmndr.git&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="creating-a-client-instance"&gt;Creating a Client Instance&lt;/h3&gt;

&lt;pre&gt;&lt;code class="python"&gt;import pyrcmmndr
pyrcmmndrClient=pyrcmmndr.RcmmndrClient("API_KEY")&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="adding-preferences"&gt;Adding Preferences&lt;/h3&gt;

&lt;pre&gt;&lt;code class="python"&gt;pyrcmmndrClient.create_preference(1,101,1.0)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will add user ‘1’ a preference of ‘1.0’ for the item ‘100’&lt;/p&gt;

&lt;h3 id="making-recommendations"&gt;Making Recommendations&lt;/h3&gt;

&lt;pre&gt;&lt;code class="python"&gt;recs=pyrcmmndrClient.get_recommendation(1)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;the dictionary ‘recs’ will contain the recommendation results as itemid,value pairs&lt;/p&gt;

&lt;h3 id="usage-statistics"&gt;Usage Statistics&lt;/h3&gt;

&lt;p&gt;You can check the usage statistics for your account as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;stats=pyrcmmndrClient.get_usage_stats()
assert stats['total_preferences'] == 1
assert stats['distinct_keys'] == 1&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="deleting-preferences"&gt;Deleting Preferences&lt;/h3&gt;

&lt;h4 id="deleting-preferences-for-specific-user"&gt;Deleting Preferences for specific user&lt;/h4&gt;

&lt;pre&gt;&lt;code class="python"&gt;pyrcmmndrClient.delete_preferences_of_user(1)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will delete all the preferences of user with id ‘1’&lt;/p&gt;

&lt;h4 id="deleting-all-preferences"&gt;Deleting All Preferences&lt;/h4&gt;

&lt;pre&gt;&lt;code class="python"&gt;pyrcmmndrClient.delete_all_preferences()&lt;/code&gt;&lt;/pre&gt;
&lt;p class="warning"&gt;This will delete all the data in your account.&lt;/p&gt;
&lt;h3 id="bulk-api"&gt;Bulk API&lt;/h3&gt;

&lt;p&gt;Bulk API is a better way of inserting many number of preference values. It is done by posting a text file (comma or tab separated) to the server.&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;pyrcmmndrClient.bulk_update_preferences('preferences.tsv')&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where the contents of preferences.tsv are similar to the following: (userID,itemID,preference)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;196,242,3
186,302,3
22,377,1
244,51,2
166,346,1&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="using-with-java"&gt;Using with Java&lt;/h2&gt;

&lt;p&gt;You can use the rest client wrapper for Java and other JVM based languages.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://github.com/Rcmmndr/java-client&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="creating-a-client-instance"&gt;Creating a Client Instance&lt;/h3&gt;

&lt;pre&gt;&lt;code class="java"&gt;rcmmndrClient = new DefaultRcmmndrClient("API_KEY");&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="creating-a-client-instance-with-custom-http-client-apache-commons"&gt;Creating a Client Instance with custom Http Client (Apache Commons)&lt;/h3&gt;

&lt;pre&gt;&lt;code class="java"&gt;rcmmndrClient = new DefaultRcmmndrClient("API_KEY",httpClientInstance);&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="adding-preferences"&gt;Adding Preferences&lt;/h3&gt;

&lt;pre&gt;&lt;code class="java"&gt;rcmmndrClient.createPreference(1l, 100l, 1.0f);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will add user ‘1’ a preference of ‘1.0’ for the item ‘100’&lt;/p&gt;

&lt;h3 id="making-recommendations"&gt;Making Recommendations&lt;/h3&gt;

&lt;pre&gt;&lt;code class="java"&gt;rcmmndrClient.getRecommendation(10l);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will return the recommendations for user 10 as a map&lt;/p&gt;

&lt;h3 id="usage-statistics"&gt;Usage Statistics&lt;/h3&gt;

&lt;pre&gt;&lt;code class="java"&gt;defaultRcmmndrClient.getUsageStats().getDistictKeys()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will return how many different users are in the system who have at least one preference&lt;/p&gt;

&lt;pre&gt;&lt;code class="java"&gt;defaultRcmmndrClient.getUsageStats().getTotalNumberOfPreferences()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will return the total number of preference objects&lt;/p&gt;

&lt;h3 id="deleting-preferences"&gt;Deleting Preferences&lt;/h3&gt;

&lt;h4 id="deleting-preferences-for-specific-user"&gt;Deleting Preferences for specific user&lt;/h4&gt;

&lt;pre&gt;&lt;code class="java"&gt;defaultRcmmndrClient.deletePreferencesOfUser(5l)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this will delete all the preferences of user 5&lt;/p&gt;

&lt;h4 id="deleting-all-preferences"&gt;Deleting All Preferences&lt;/h4&gt;

&lt;pre&gt;&lt;code class="java"&gt;defaultRcmmndrClient.deleteAllPreferences()&lt;/code&gt;&lt;/pre&gt;
&lt;p class="warning"&gt;This will delete all the data in your account.&lt;/p&gt;
&lt;h3 id="bulk-api"&gt;Bulk API&lt;/h3&gt;

&lt;p&gt;Bulk API is a better way of inserting many number of preference values. It is done by posting a text file (comma or tab separated) to the server.&lt;/p&gt;

&lt;pre&gt;&lt;code class="java"&gt;defaultRcmmndrClient.bulkUpdatePreferences(new FileInputStream(new File("…/preferences.tsv")))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where the contents of preferences.tsv are similar to the following: (userID,itemID,preference)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;196,242,3
186,302,3
22,377,1
244,51,2
166,346,1&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="using-with-clojure"&gt;Using with Clojure&lt;/h2&gt;

&lt;p&gt;There is a ready to run clojure webapp sample located here:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://github.com/Rcmmndr/rcmmndr-clojure-sample&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This sample is currently using the Java client&lt;/p&gt;

&lt;h2 id="monitoring"&gt;Monitoring&lt;/h2&gt;

&lt;p&gt;You can access the Rcmmndr dashboard from the CLI.&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:open rcmmndr&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="migrating-between-plans"&gt;Migrating between plans&lt;/h2&gt;
&lt;div class="note"&gt;
&lt;p&gt;Application owners should carefully manage the migration timing to ensure proper application function during the migration process.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Use the &lt;code&gt;heroku addons:upgrade&lt;/code&gt; command to migrate to a new plan.&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:upgrade rcmmndr:basic
-----&amp;gt; Upgrading rcmmndr:basic to sharp-mountain-4005... done, v18 ($49/mo)
       Your plan has been updated to: rcmmndr:basic&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="removing-the-addon"&gt;Removing the add-on&lt;/h2&gt;

&lt;p&gt;Rcmmndr can be removed via the CLI.&lt;/p&gt;
&lt;div class="warning"&gt;
&lt;p&gt;This will destroy all associated data and cannot be undone!&lt;/p&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:remove rcmmndr
-----&amp;gt; Removing rcmmndr from sharp-mountain-4005... done, v20 (free)&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="support"&gt;Support&lt;/h2&gt;

&lt;p&gt;All Rcmmndr support and runtime issues should be submitted via on of the &lt;a href="https://devcenter.heroku.com/support-channels"&gt;Heroku Support channels&lt;/a&gt;. Any non-support related issues or product feedback is welcome at support@rcmmndr.com&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/yuRpgyaEu24" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/rcmmndr</feedburner:origLink></entry>
  <entry>
    <id>tag:devcenter.heroku.com,2005:Article/1670</id>
    <published>2013-05-22T16:07:09Z</published>
    <updated>2013-05-22T16:07:09Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/UaJMvEtKCRs/add-on-plan-creation" />
    <title>Add-on Plan Creation</title>
    <content type="html">&lt;p&gt;Add-on Providers can create Add-on plans using the &lt;a href="https://addons.heroku.com/provider/dashboard"&gt;Add-on Provider interface&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Care should be taken when creating plans since they are immutable. Plans must be immutable since there is no support for updating the name or price of a plan once it has been installed. &lt;/p&gt;

&lt;p&gt;Once an add-on plan has been created, it is eligible for installation by any one of our &lt;a href="https://devcenter.heroku.com/articles/heroku-beta-features"&gt;beta&lt;/a&gt; or &lt;a href="https://addons.heroku.com/provider/resources/business/becoming"&gt;alpha&lt;/a&gt; users.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/UaJMvEtKCRs" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/add-on-plan-creation</feedburner:origLink></entry>
  <entry>
    <id>tag:devcenter.heroku.com,2005:Article/1671</id>
    <published>2013-05-21T21:54:02Z</published>
    <updated>2013-05-23T10:35:41Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/sWnbGD1n_rQ/add-on-provider-api" />
    <title>Add-on Provider API</title>
    <content type="html">&lt;p&gt;The Add-on Provider API is used when Heroku calls your add-on service. In these examples Heroku is issuing the requests and your add-on is providing the responses.&lt;/p&gt;

&lt;p&gt;All calls should be protected by HTTP basic auth with the add-on id and password specified in your add-on manifest. All calls are required.&lt;/p&gt;

&lt;h2 id="provision"&gt;Provision&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;Request: POST https://username:password@api.heroku.com/heroku/resources
Request Body: {
  "heroku_id": "app123@heroku.com",
  "plan": "basic",
  "region": "amazon-web-services::us-east-1",
  "callback_url": "https://api.heroku.com/vendor/apps/app123%40heroku.com",
  "logplex_token": "t.abc123",
  "options": {}
}
Response Body: {
  "id": 456,
  "config": {"MYADDON_URL": "http://myaddon.com/52e82f5d73"},
  "message": "your message here"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Only information which is immutable between requests is provided at the time of provisioning.
If you wish to access information which can change (e.g., owner email address or application name) then it is available, after the API has returned a 200 response to Heroku, via the &lt;a href="https://addons.heroku.com/provider/resources/technical/reference/app-info"&gt;App Info API&lt;/a&gt;. It is the responsibility of the provider to periodically check this endpoint to ensure data is consistent.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;region&lt;/code&gt; attribute in the request specifies geographical region of the app that the add-on is being provisioned to. Use this to provision the resource in geopgraphical proximity to the app, ignore it (if your add-on is not latency sensitive) or respond with an error if your add-on does not support apps in the region specified.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;logplex_token&lt;/code&gt; attribute is provided so that logs can be sent to the app's log stream. For more information, see the article describing logplex input.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;options&lt;/code&gt; object in the request are extra command line options passed in to the &lt;code&gt;heroku addons:add&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;id&lt;/code&gt; value returned in the response may be a string or integer value. It should be an
immutable value that can be used to address the relationship between this app and resource. This means that a plan change can &lt;em&gt;not&lt;/em&gt; change the value of this &lt;code&gt;id&lt;/code&gt;, you can however update the
&lt;code&gt;config&lt;/code&gt; later to point the app to a different resource.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;config&lt;/code&gt; object and &lt;code&gt;message&lt;/code&gt; in the response are both optional.&lt;/p&gt;

&lt;p&gt;Heroku can also pass &lt;a href="https://addons.heroku.com/provider/resources/technical/reference/advanced-features"&gt;command-line parameters&lt;/a&gt; given to the addons:add action during add-on provisioning to the add-on provider. Providers that require access to &lt;a href="https://addons.heroku.com/provider/resources/technical/reference/advanced-features"&gt;advanced features&lt;/a&gt; will receive additional attributes based on the features they've requested.&lt;/p&gt;

&lt;h2 id="plan-change"&gt;Plan change&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;Request: PUT https://username:password@api.heroku.com/heroku/resources/:id
Request Body: {"heroku_id": "app123@heroku.com", "plan": "premium"}
Response Body: {"config": { ... }, "message": "your message here"}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The config object and message in the response are both optional.&lt;/p&gt;

&lt;h2 id="deprovision"&gt;Deprovision&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;Request: DELETE https://username:password@api.heroku.com/heroku/resources/:id
Request Body: none
Response Status: 200
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="exceptions"&gt;Exceptions&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;Request: https://username:password@api.heroku.com/
Request Body: any
Response Status: 422
Response Body: { "message": "your message here" }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For 422 and 503 responses the message property from your JSON response will be
displayed to the user. For all other responses, and when no message property is available,
a standard error message will displayed.&lt;/p&gt;

&lt;h2 id="single-sign-on"&gt;Single sign-on&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;Request: POST https://username:password@api.heroku.com/sso/login/
Request Body: id=&amp;lt;id&amp;gt;&amp;amp;token=&amp;lt;token&amp;gt;&amp;amp;timestamp=&amp;lt;ts&amp;gt;&amp;amp;nav-data=&amp;lt;data&amp;gt;&amp;amp;email=&amp;lt;user-email&amp;gt;&amp;amp;app=&amp;lt;app-name&amp;gt;&amp;amp;other=vals
Response Header: Set-Cookie: heroku-nav-data=&amp;lt;data&amp;gt;
Response Body: Web view for logged-in user
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Optional values can be passed through by appending them to the Heroku API SSO URL. Users can be automatically logged in to and add-on dashboard via SSO by directing them to&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;https://api.heroku.com/myapps/&amp;lt;heroku_app_id&amp;gt;/addons/&amp;lt;addon-name&amp;gt;?other=vals
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See &lt;a href="https://addons.heroku.com/provider/resources/technical/reference/manifest"&gt;manifest formats&lt;/a&gt; for more information about configuring single sign-on via GET or POST.&lt;/p&gt;

&lt;h2 id="list-apps"&gt;List Apps&lt;/h2&gt;

&lt;p&gt;This endpoint returns a list of apps that have installed your add-on.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Request: GET https://username:password@api.heroku.com/vendor/apps
Response Body: [
  { "provider_id": "1", 
    "heroku_id": "app123@heroku.com", 
    "callback_url": "https://api.heroku.com/vendor/apps/app123%40heroku.com", 
    "plan": "test" 
  },
  { "provider_id": "3", 
    "heroku_id": "app456@heroku.com", 
    "callback_url": "https://api.heroku.com/vendor/apps/app456%40heroku.com", 
    "plan": "premium" 
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="pagination"&gt;Pagination&lt;/h3&gt;

&lt;p&gt;Results larger than 4000 will be paginated. Pagination information is passed
via the &lt;code&gt;Link&lt;/code&gt; HTTP header. Use those URIs to navigate the pagination rather
than constructing them in your client code.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Link: &amp;lt;https://api.heroku.com/vendor/apps?offset=100&amp;gt;; rel="prev",
      &amp;lt;https://api.heroku.com/vendor/apps?offset=1000&amp;gt;; rel="next"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The possible &lt;code&gt;rel&lt;/code&gt; values within that header are:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;next&lt;/code&gt;: Shows the URL of the immediate next page of results.&lt;br&gt;&lt;code&gt;prev&lt;/code&gt;: Shows the URL of the immediate previous page of results.&lt;/p&gt;

&lt;h2 id="app-info"&gt;App Info&lt;/h2&gt;

&lt;p&gt;This endpoint returns app information for an app which has installed the Add-on. Information returned is mutable and should be updated when the most recent data is required.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Request: GET https://username:password@api.heroku.com/vendor/apps/:heroku_id
Response Body: { 
  "id": "app123@heroku.com",
  "name": "myapp", 
  "config": {"MYADDON_URL": "http://myaddon.com/52e82f5d73"}, 
  "callback_url": "https://api.heroku.com/vendor/apps/app123%40heroku.com", 
  "owner_email": "user@email.com",
  "region": "amazon-web-services::us-east-1",
  "logplex_token": "t.abc123",
  "domains": ["www.the-consumer.com", "the-consumer.com"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="update-config-vars"&gt;Update config Vars&lt;/h2&gt;

&lt;p&gt;This endpoint allows the Add-on provider to update the config vars defined in the Add-on provider's manifest.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Request: PUT https://username:password@api.heroku.com/vendor/apps/:heroku_id 
Request Body : { "config": {"MYADDON_URL": "http://myaddon.com/ABC123"}}
Response: 200 OK
&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/sWnbGD1n_rQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/add-on-provider-api</feedburner:origLink></entry>
  <entry>
    <id>tag:devcenter.heroku.com,2005:Article/1356</id>
    <published>2013-05-13T19:09:13Z</published>
    <updated>2013-05-21T05:15:56Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/HH4S4pKZTCo/postmark" />
    <title>Postmark</title>
    <content type="html">&lt;p&gt;&lt;a href="http://addons.heroku.com/postmark"&gt;Postmark&lt;/a&gt; &lt;a href="http://addons.heroku.com"&gt;add-on&lt;/a&gt; removes the headaches of delivering and parsing transactional email for your web app, with minimal setup time and zero maintenance. We have years of experience getting email to the inbox, so you can focus on what you do best.&lt;/p&gt;

&lt;p&gt;Use our Send API or our simple SMTP interface to start sending in minutes. Our Inbound API parses incoming email and forwards it to you via a web hook, making it easy to handle incoming email in your application.&lt;/p&gt;

&lt;h2 id="provisioning-the-addon"&gt;Provisioning the add-on&lt;/h2&gt;

&lt;p&gt;Postmark can be attached to a Heroku application via the CLI:&lt;/p&gt;
&lt;div class="callout"&gt;
&lt;p&gt;A list of all plans available can be found &lt;a href="http://addons.heroku.com/postmark"&gt;on the Postmark add-on page&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:add postmark:10k
-----&amp;gt; Adding postmark to sharp-mountain-4005... done, v18 (free)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once Postmark has been added a &lt;code&gt;POSTMARK_API_KEY&lt;/code&gt; setting will be available in the app configuration and will contain the api key to access Postmark API or SMTP interface. This can be confirmed using the &lt;code&gt;heroku config:get&lt;/code&gt; command.&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku config:get POSTMARK_API_KEY
22874e6c-32f8-4e30-a0ee-45e1ed144a6b&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After installing the Postmark add-on you also need to create at least one sender signature and configure your application to fully integrate with the add-on.&lt;/p&gt;

&lt;h2 id="creating-sender-signatures"&gt;Creating sender signatures&lt;/h2&gt;

&lt;p&gt;Sender signatures are required in order to verify that, well, you really own the mailbox, and that you are not a spammer (yes, we hate spam too). You must have a sender signature for each from address used in your application.&lt;/p&gt;

&lt;p&gt;To create a sender signature, open the Postmark Dashboard from the terminal:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:open postmark
Opening postmark for sharp-mountain-4005…&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also proceed to the Postmark Dashboard from your application page on the Heroku web site.&lt;/p&gt;

&lt;h2 id="setting-up-a-local-development-environment"&gt;Setting up a local development environment&lt;/h2&gt;

&lt;p&gt;Postmark automatically sets environment variables on your Heroku servers, but sometimes you may need to recreate the environment locally. &lt;a href="https://devcenter.heroku.com/articles/config-vars#local-setup"&gt;Foreman&lt;/a&gt; aims to solve this for you. You can save the environment variables in your &lt;code&gt;.env&lt;/code&gt; file and let Foreman do the rest.&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;  $ bash -c 'echo "POSTMARK_API_KEY=`heroku config:get POSTMARK_API_KEY`" &amp;gt;&amp;gt; .env'
  $ bash -c 'echo "POSTMARK_SMTP_SERVER=`heroku config:get POSTMARK_SMTP_SERVER`" &amp;gt;&amp;gt; .env'
  $ bash -c 'echo "POSTMARK_INBOUND_ADDRESS=`heroku config:get POSTMARK_INBOUND_ADDRESS`" &amp;gt;&amp;gt; .env'&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="sending-emails-via-the-postmark-smtp-interface"&gt;Sending emails via the Postmark SMTP interface&lt;/h2&gt;

&lt;p&gt;You want to try Postmark, but your application uses SMTP to send email? You can instantly switch your current email delivery without having to modify the application. This feature lets you use plain SMTP to send your messages and, to use it, you need to only change your configuration to point to the Postmark SMTP server.&lt;/p&gt;

&lt;p&gt;The SMTP listener endpoint is available at smtp.postmarkapp.com on port 25 and 2525 (to get around firewall issues). We support both plain text authentication and CRAM-MD5. We recommend the latter as it is a lot more secure. CRAM-MD5 encrypts just the authentication process, but the message content is still sent as plain text. You can encrypt the entire connection using TLS via the standard STARTTLS SMTP extension. STARTTLS is supported by the vast majority of mailers and some of them, like Ruby’s ActionMailer automatically switch to encrypted communication when they detect that the server supports it.&lt;/p&gt;

&lt;p&gt;Here is a sample configuration for Ruby Mail library:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;Mail.defaults do
  delivery_method :smtp, {
    :address =&amp;gt; ENV['POSTMARK_SMTP_SERVER'],
    :port =&amp;gt; '25',
    :domain =&amp;gt; 'yourapp.heroku.com',
    :user_name =&amp;gt; ENV['POSTMARK_API_KEY'],
    :password =&amp;gt; ENV['POSTMARK_API_KEY'],
    :authentication =&amp;gt; :plain,
    :enable_starttls_auto =&amp;gt; true
  }
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And Rails/ActionMailer:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;ActionMailer::Base.smtp_settings = {
  :port           =&amp;gt; '25',
  :address        =&amp;gt; ENV['POSTMARK_SMTP_SERVER'],
  :user_name      =&amp;gt; ENV['POSTMARK_API_KEY'],
  :password       =&amp;gt; ENV['POSTMARK_API_KEY'],
  :domain         =&amp;gt; 'yourapp.heroku.com',
  :authentication =&amp;gt; :plain,
}
ActionMailer::Base.delivery_method = :smtp&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="sending-emails-in-ruby"&gt;Sending emails in Ruby&lt;/h3&gt;

&lt;p&gt;We support the official Ruby gem called &lt;code&gt;postmark&lt;/code&gt;. It’s integrated with the Ruby Mail library and requires it to be installed. You can install both manually using the following command:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ gem install mail postmark&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If your application is using Bundler, add the following entries to your Gemfile and update application dependencies with &lt;code&gt;bundle install&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;gem 'mail'
gem 'postmark'&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The following example will use the gem to send a text email with attachments:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;message = Mail.new do
  from            'leonard@bigbangtheory.com'
  to              'Dr. Sheldon Cooper &amp;lt;sheldon@bigbangtheory.com&amp;gt;'
  subject         'Have you seen these pictures of yours?'
  body            'You look like a geek!'
  add_file        '1.jpeg'

  delivery_method Mail::Postmark, :api_key =&amp;gt; ENV['POSTMARK_API_KEY']
end

message.attachments['sheldon.jpeg'] = File.read('2.jpeg')

message.deliver
# =&amp;gt; #&amp;lt;Mail::Message:70185826686240, Multipart: true, Headers: &amp;lt;From: leonard@bigbangtheory.com&amp;gt;, &amp;lt;To: sheldon@bigbangtheory.com&amp;gt;, &amp;lt;Message-ID: ba644cc1-b5b1-4bcb-aaf8-2f290b5aad80&amp;gt;, &amp;lt;Subject: Have you seen these pictures of yours?&amp;gt;, &amp;lt;Content-Type: multipart/mixed; boundary=--==_mimepart_5121f9f1ec653_12c53fd569035ad817726&amp;gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="sending-emails-in-ruby-on-rails-3x"&gt;Sending emails in Ruby on Rails 3.x&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;postmark-rails&lt;/code&gt; Ruby gem was designed to make switching to the Postmark API as easy as possible. Ruby on Rails applications will need to add the following entry into their &lt;code&gt;Gemfile&lt;/code&gt; specifying the Postmark client library.&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;gem 'postmark-rails'&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Update application dependencies with bundler.&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ bundle install&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add this to your config/application.rb:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;config.action_mailer.delivery_method   = :postmark
config.action_mailer.postmark_settings = { :api_key =&amp;gt; ENV['POSTMARK_API_KEY'] }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s it. Now send emails as usual.&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;class TestMailer &amp;lt; ActionMailer::Base

  def tagged_message
    mail(
      :subject =&amp;gt; 'Did you know Postmark has a Heroku add-on?',
      :to      =&amp;gt; 'sheldon@bigbangtheory.com',
      :from    =&amp;gt; 'leonard@bigbangtheory.com',
      :tag     =&amp;gt; 'my-tag'
    )
  end

end&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="sending-emails-in-ruby-on-rails-2x"&gt;Sending emails in Ruby on Rails 2.x&lt;/h2&gt;

&lt;p&gt;Rails 2.x applications will need to add the following to &lt;code&gt;config/environment.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;Rails::Initializer.run do |config|

  # ...

  config.gem 'postmark-rails'
  require    'postmark-rails'

  config.action_mailer.postmark_api_key = ENV['POSTMARK_API_KEY']
  config.action_mailer.delivery_method  = :postmark

  # ...

end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Usage example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;class SuperMailer &amp;lt; ActionMailer::Base

  def email
    from       "leonard@bigbangtheory.com"
    subject    "Hello from Postmark"
    recipients "sheldon@bigbangtheory.com"
    tag        "big-bang"
  end

end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See the &lt;a href="https://github.com/wildbit/postmark-rails/blob/master/README.rdoc"&gt;postmark-rails gem documentation&lt;/a&gt; for more examples.&lt;/p&gt;

&lt;h2 id="sending-emails-in-python"&gt;Sending emails in Python&lt;/h2&gt;

&lt;p&gt;Python users will need to install the &lt;a href="https://github.com/themartorana/python-postmark/"&gt;python-postmark library&lt;/a&gt;. It’s possible to install the library from PyPy:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ pip install python-postmark&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The following example will use the python-postmark library to send a tagged email.&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;import os
from postmark import PMMail

message = PMMail(api_key = os.environ.get('POSTMARK_API_KEY'),
                 subject = "Hello from Postmark",
                 sender = "leonard@bigbangtheory.com",
                 to = "sheldon@bigbangtheory.com",
                 text_body = "Hello",
                 tag = "hello")

message.send()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Check out the PMMail class’ documentation for more information on usage.&lt;/p&gt;

&lt;h2 id="sending-emails-in-nodejs"&gt;Sending emails in NodeJS&lt;/h2&gt;

&lt;p&gt;NodeJS users can use the &lt;a href="https://github.com/voodootikigod/postmark.js"&gt;postmark package&lt;/a&gt; available to install using NPM:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ npm install postmark&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The following example will use the postmark package for NodeJS to send a tagged text email:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;var postmark = require("postmark")(process.env.POSTMARK_API_KEY)

postmark.send({
    "From": "leonard@bigbangtheory.com",
    "To": "sheldon@bigbangtheory.com",
    "Subject": "Hello from Postmark",
    "TextBody": "Hello!",
    "Tag": "big-bang"
}, function(error, success) {
    if(error) {
        console.error("Unable to send via postmark: " + error.message);
       return;
    }
    console.info("Sent to postmark for delivery")
});&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="sending-emails-in-clojure"&gt;Sending emails in Clojure&lt;/h2&gt;

&lt;p&gt;Clojure users can use &lt;a href="http://sjl.bitbucket.org/clojure-postmark/"&gt;clojure-postmark&lt;/a&gt; to interact with the API. To get started add the following entry to your project dependencies (we assume you’re using Leiningen):&lt;/p&gt;

&lt;pre&gt;&lt;code class="clojure"&gt;[postmark "1.1.0"]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The following example will use the clojure-postmark library to send a tagged text email:&lt;/p&gt;

&lt;pre&gt;&lt;code class="clojure"&gt;(use '[postmark.core :only (postmark)])

(def api-key (get (System/getenv) "POSTMARK_API_KEY"))

(def send-message (postmark api-key "leonard@bigbangtheory.com"))

(send-message {:to "sheldon@bigbangtheory.com"
               :subject "Hello from Postmark"
               :text "Hello!"
               :tag "big-bang"})&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="using-postmark-inbound"&gt;Using Postmark Inbound&lt;/h2&gt;

&lt;p&gt;Postmark makes email parsing easy, too. We provide you with a unique inbound email address, which can be used for receiving emails. Postmark then parses the incoming emails and sends you the data in a nicely formatted JSON document via web hook. To see it, run:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku config:get POSTMARK_INBOUND_ADDRESS
3e5317xxxx48ce3bxxxx1a7be74f665f@inbound.postmarkapp.com&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Depending on your use, you may not want your users to see the &lt;em&gt;@inbound.postmarkapp.com&lt;/em&gt; email. There are two options: MX Record Forwarding (beta) and custom forwarding with Gmail/Google Apps.&lt;/p&gt;

&lt;p&gt;Our MX Record Support is in beta until we’ve released a web-based configuration UI. It’s currently API-only, and you can read the &lt;a href="http://developer.postmarkapp.com/developer-inbound-mx.html"&gt;documentation on configuring MX Records&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’d like to wait until the feature is included in Postmark’s UI, or if you do not have access to edit your DNS records, you can read our help article to learn how to &lt;a href="http://support.postmarkapp.com/customer/portal/articles/304511-configuring-a-custom-email-address-forward-with-gmail"&gt;configure a custom forwarding email address&lt;/a&gt; from your Gmail/Google Apps account.&lt;/p&gt;

&lt;p&gt;In order for your application receive the emails that we parse, you will need to tell Postmark where to send the JSON data for each inbound email it processes, which is done via an HTTP POST to a URL of your choice. You can set this URL in the Settings page for your Postmark server on the Postmark Dashboard.&lt;/p&gt;

&lt;p&gt;To test your inbound server, we recommend using &lt;a href="http://requestb.in/"&gt;RequestBin&lt;/a&gt; first.&lt;/p&gt;

&lt;p&gt;Here is a simple Ruby/Sinatra application that does basic inbound processing:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;require 'sinatra'
require 'json'
require 'logger'

logger = Logger.new(STDOUT)

class Comment
  attr_accessor :attributes

  def self.create_from_inbound_hook(message)
    self.new(:text =&amp;gt; message["TextBody"],
             :user_email =&amp;gt; message["From"],
             :discussion_id =&amp;gt; message["MailboxHash"])
  end

  def initialize(attributes={})
    @attributes = attributes
  end
end

post '/inbound' do
  request.body.rewind
  comment = Comment.create_from_inbound_hook(JSON.parse(request.body.read))
  logger.info comment.inspect
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s assume the inbound hook is set to &lt;code&gt;http://myapp.heroku.com/inbound&lt;/code&gt;. Then, if a user sends an email to &lt;code&gt;3e5317xxxx48ce3bxxxx1a7be74f665f+discussion7864@inbound.postmarkapp.com&lt;/code&gt; (the part after plus sign is called “mailbox hash” and can be used to transfer additional information), it will be processed by Postmark and forwarded to the app’s inbound hook as a JSON object. The example app creates a new instance of Comment object using JSON object provided by Postmark.&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;:::ruby    
I, [2013-02-28T05:18:56.407910 #2]  INFO -- : #&amp;lt;Comment:0x00000002979260 @attributes={:text=&amp;gt;"That's what you said about the Green Lantern movie. You were 114 minutes of wrong. ", :user_email=&amp;gt;"sheldon@bigbangtheory.com", :discussion_id=&amp;gt;"discussion7864"}&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="migrating-between-plans"&gt;Migrating between plans&lt;/h2&gt;
&lt;div class="note"&gt;
&lt;p&gt;Application owners should carefully manage the migration timing to ensure proper application function during the migration process.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Use the &lt;code&gt;heroku addons:upgrade&lt;/code&gt; command to migrate to a new plan.&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:upgrade postmark:gold
-----&amp;gt; Upgrading postmark:newplan to sharp-mountain-4005... done, v18 ($49/mo)
       Your plan has been updated to: postmark:gold&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="removing-the-addon"&gt;Removing the add-on&lt;/h2&gt;

&lt;p&gt;Postmark can be removed via the CLI.&lt;/p&gt;
&lt;div class="warning"&gt;
&lt;p&gt;This will destroy all associated data and cannot be undone!&lt;/p&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:remove postmark
-----&amp;gt; Removing postmark from sharp-mountain-4005... done, v20 (free)&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="support"&gt;Support&lt;/h2&gt;

&lt;p&gt;If you need help or have questions, you can contact Postmark at any time at &lt;a href="mailto:support@postmarkapp.com"&gt;support@postmarkapp.com&lt;/a&gt; or &lt;a href="http://twitter.com/postmarkapp"&gt;@postmarkapp&lt;/a&gt; on Twitter. For system status, visit &lt;a href="http://status.postmarkapp.com"&gt;http://status.postmarkapp.com&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/HH4S4pKZTCo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/postmark</feedburner:origLink></entry>
  <entry>
    <id>tag:devcenter.heroku.com,2005:Article/1643</id>
    <published>2013-05-07T13:44:25Z</published>
    <updated>2013-05-08T09:16:21Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/d1vpQU51UOs/s3-upload-python" />
    <title>Direct to S3 File Uploads in Python</title>
    <content type="html">&lt;p&gt;Web applications often require the ability to allow users to upload files such as images, movies and archives.  Amazon S3 is a popular and reliable storage option for these files.&lt;/p&gt;

&lt;p&gt;This article demonstrates how to create a Python application that uploads files directly to S3 instead of via a web application, utilising S3's Cross-Origin Resource Sharing (CORS) support.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;A complete example of the code discussed in this article is available for direct use in this &lt;a href="https://github.com/flyingsparx/FlaskDirectUploader"&gt;Github repository&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id="uploading-directly-to-s3"&gt;Uploading directly to S3&lt;/h2&gt;

&lt;p&gt;The main advantage of direct uploading is that the load on your application's dynos would be considerably reduced. Using server-side processes for receiving files and transferring to S3 can needlessly tie up your dynos and will mean that they will not be able to respond to simultaneous web requests as efficiently.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;If your application relies on some form of file processing between the client's computer and S3 (such as parsing Exif information or applying watermarks to images), then you may need to employ the use of extra dynos and consider the &lt;a href="https://code.google.com/p/boto"&gt;boto&lt;/a&gt; Python library for handling the S3 upload.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The application uses client-side JavaScript and Python for signing the requests. It will therefore be a suitable guide for developing applications for the Flask, Bottle and Django web frameworks. The upload is carried out asynchronously so that you can decide how to handle your application's flow after the upload has completed (for example,  a page redirect upon successful upload rather than a full page refresh).&lt;/p&gt;

&lt;p&gt;An example simple account-editing scenario is used as a guide for completing the various steps required to accomplish the direct upload and to relate the application of this to a wider range of use-cases. More information on this scenario is provided later.&lt;/p&gt;

&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;

&lt;p&gt;S3 is comprised of a set of buckets, each with a globally unique name, in which individual files (known as objects) and directories, can be stored.&lt;/p&gt;

&lt;p&gt;For uploading files to S3, you will need an Access Key ID and a Secret Access Key, which act as a username and password. The access key account will need to have sufficient access privileges to the target bucket in order for the upload to be successful.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;Please see the &lt;a href="https://devcenter.heroku.com/articles/s3"&gt;S3 Article&lt;/a&gt; for more information on this, creating buckets and finding your Access Key ID and Secret Access Key.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The method described in this article involves the use of client-side JavaScript and server-side Python. In general, the completed image-upload process follows these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A file is selected for upload by the user in their web browser;&lt;/li&gt;
&lt;li&gt;JavaScript is then responsible for making a request to your web application on Heroku, which produces a temporary signature with which to sign the upload request;&lt;/li&gt;
&lt;li&gt;The temporary signed request is returned to the browser in JSON format;&lt;/li&gt;
&lt;li&gt;JavaScript then uploads the file directly to Amazon S3 using the signed request supplied by your Python application.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;This guide includes information on how to implement the client-side and server-side code to form the complete system. After following the guide, you should have a working barebones system, allowing your users to upload files to S3. However, it is usually worth adding extra functionality to help improve the security of the system and to tailor it for your own particular uses. Pointers for this are mentioned in the appropriate parts of the guide.&lt;/p&gt;

&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://toolbelt.heroku.com/"&gt;Heroku Toolbelt&lt;/a&gt; has been installed;&lt;/li&gt;
&lt;li&gt;A Heroku application has been created for the current project;&lt;/li&gt;
&lt;li&gt;An AWS S3 bucket has been created.&lt;/li&gt;
&lt;/ul&gt;&lt;h2 id="initial-setup"&gt;Initial setup&lt;/h2&gt;

&lt;h3 id="heroku-setup"&gt;Heroku setup&lt;/h3&gt;

&lt;p&gt;In order for your application to access the AWS credentials for signing upload requests, they will need to be added as configuration variables in Heroku:&lt;/p&gt;

&lt;div class="callout"&gt;
&lt;p&gt;If you are testing locally before deployment, remember to add the credentials to your local machine's environment, too.&lt;/p&gt;
&lt;/div&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku config:set AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=yyy
Adding config vars and restarting app... done, v21
    AWS_ACCESS_KEY_ID     =&amp;gt; xxx
    AWS_SECRET_ACCESS_KEY =&amp;gt; yyy
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In addition to the AWS access credentials, set your target S3 bucket's name:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku config:add S3_BUCKET = zzz
Adding config vars and restarting app... done, v21
    S3_BUCKET     =&amp;gt; zzz
&lt;/code&gt;&lt;/pre&gt;

&lt;div class="warning"&gt;
&lt;p&gt;Using config vars is preferable over configuration files for security reasons. Try to avoid placing passwords and access keys directly in your application's code or in configuration files.&lt;/p&gt;
&lt;/div&gt;

&lt;h3 id="s3-setup"&gt;S3 setup&lt;/h3&gt;

&lt;p&gt;You will now need to edit some of the permissions properties of the target S3 bucket so that the final request has sufficient privileges to write to the bucket. In a web-browser, sign in to the AWS console and select the S3 section. Select the appropriate bucket and click the ‘Properties’ tab. Select the Permissions section and three options are provided (Add more permissions, Edit bucket policy and Edit CORS configuration). &lt;/p&gt;

&lt;p&gt;CORS (Cross-Origin Resource Sharing) will allow your application to access content in the S3 bucket. Each rule should specify a set of domains from which access to the bucket is granted and also the methods and headers permitted from those domains. &lt;/p&gt;

&lt;p&gt;&lt;img src="https://github.com/flyingsparx/FlaskDirectUploader/blob/master/static/guide-screenshots/cors1.png?raw=true" alt="Locating the ‘Properties’ tab and CORS configuration editor"&gt;&lt;/p&gt;

&lt;p&gt;For this to work in your application, click 'Add CORS Configuration' and enter the following XML:&lt;/p&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"&amp;gt;
   &amp;lt;CORSRule&amp;gt;
        &amp;lt;AllowedOrigin&amp;gt;yourdomain.com&amp;lt;/AllowedOrigin&amp;gt;
        &amp;lt;AllowedMethod&amp;gt;GET&amp;lt;/AllowedMethod&amp;gt;
        &amp;lt;AllowedMethod&amp;gt;POST&amp;lt;/AllowedMethod&amp;gt;
        &amp;lt;AllowedMethod&amp;gt;PUT&amp;lt;/AllowedMethod&amp;gt;
        &amp;lt;AllowedHeader&amp;gt;*&amp;lt;/AllowedHeader&amp;gt;
    &amp;lt;/CORSRule&amp;gt;
&amp;lt;/CORSConfiguration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Click 'Save' in the CORS window and then 'Save' again in the bucket's 'Properties' tab.&lt;/p&gt;

&lt;p&gt;This tells S3 to allow any domain access to the bucket and that requests can contain any headers. For security, you can change the 'AllowedOrigin' to only accept requests from your domain.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;If you wish to use S3 credentials specifically for this application, then more keys can be generated in the AWS account pages. This provides further security, since you can designate a very specific set of requests that this set of keys are able to perform. If this is preferable to you, then you will need to also set up an IAM user in the Edit bucket policy option in your S3 bucket. There are various guides on AWS's web pages detailing how this can be accomplished.&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id="direct-uploading"&gt;Direct uploading&lt;/h2&gt;

&lt;p&gt;The processes and steps required to accomplish a direct upload to S3 will be demonstrated through the use of a simple profile-editing scenario for the purposes of this article. This example will involve the user being permitted to select an avatar image to upload and enter some basic information to be stored as part of their account.&lt;/p&gt;

&lt;p&gt;In this scenario, the following procedure will take place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user is presented with a web page, containing elements encouraging the user to choose an image to upload as their avatar and to enter a username and their own name.&lt;/li&gt;
&lt;li&gt;An element is responsible for maintaining a preview of the chosen image by the user. By default, and if no image is chosen for upload, a default avatar image is used instead (making the image-upload effectively optional to the user in this scenario).&lt;/li&gt;
&lt;li&gt;When a user selects an image to be uploaded, the upload to S3 is handled automatically and asynchronously with the process described earlier in this article. The image preview is then updated with the selected image once the upload is complete and successful.&lt;/li&gt;
&lt;li&gt;The user is then free to move on to filling in the rest of the information.&lt;/li&gt;
&lt;li&gt;The user then clicks the “submit” button, which posts the username, name and the URL of the uploaded image to the Python application to be checked and/or stored. If no image was uploaded by the user earlier the default avatar image URL is posted instead.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;img src="https://github.com/flyingsparx/FlaskDirectUploader/blob/master/static/guide-screenshots/account1.png?raw=true" alt="An example of what the simple finished product will consist of"&gt;&lt;/p&gt;

&lt;h3 id="setting-up-the-client-side-code"&gt;Setting up the client-side code&lt;/h3&gt;

&lt;p&gt;This setup does not require any additional, non-standard Python libraries, but some scripts are necessary to complete the implementation on the client-side. &lt;/p&gt;

&lt;p&gt;This article covers the use of the &lt;code&gt;s3upload.js&lt;/code&gt; script. Obtain this script from the &lt;a href="https://github.com/tadruj/s3upload-coffee-javascript"&gt;project's repo&lt;/a&gt; (using Git or otherwise) and store it somewhere appropriate in your application's static directory.
This script currently depends on both the &lt;a href="http://jquery.com/download/"&gt;JQuery&lt;/a&gt; and &lt;a href="http://lodash.com/"&gt;Lo-Dash&lt;/a&gt; libraries. Inclusion of these in your application will be covered later on in this guide.&lt;/p&gt;

&lt;p&gt;The HTML and JavaScript can now be created to handle the file selection, obtain the request and signature from your Python application, and then finally make the upload request. &lt;/p&gt;

&lt;p&gt;Firstly, create a file called &lt;code&gt;account.html&lt;/code&gt; in your application's templates directory and populate the &lt;code&gt;head&lt;/code&gt; and other necessary HTML tags appropriately for your application. In the body of this HTML file, include a file input and an element that will contain status updates on the upload progress. In addition to this, create a form to allow the user to enter their username and full name and a hidden &lt;code&gt;input&lt;/code&gt; element to hold the URL of the chosen avatar image:&lt;/p&gt;

&lt;div class="callout"&gt;
&lt;p&gt;To see the completed HTML file, please see the appropriate code in the companion &lt;a href="https://github.com/flyingsparx/FlaskDirectUploader/blob/master/templates/account.html"&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;pre&gt;&lt;code class="html"&gt;&amp;lt;input type="file" id="file" onchange="s3_upload();"/&amp;gt;
&amp;lt;p id="progress"&amp;gt;Please select a file```
&amp;lt;div id="preview"&amp;gt;&amp;lt;img src="/static/default.png"  /&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;form method="POST" action="/submit_form/"&amp;gt;
    &amp;lt;input type="hidden" id="avatar_url" name="avatar_url" value="/static/default.png" /&amp;gt;
    &amp;lt;input type="text" name="username" placeholder="Username" /&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;input type="text" name="full_name" placeholder="Full name" /&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;input type="submit" value="Update profile" /&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;preview&lt;/code&gt; element initially holds a default avatar image (which would become the user’s avatar if a new image is not chosen), and the &lt;code&gt;avatar_url&lt;/code&gt; input maintains the current URL of the user’s chosen avatar image. Both of these are updated by the JavaScript, discussed below, when the user selects a new avatar. &lt;/p&gt;

&lt;p&gt;Thus when the user finally clicks the submit button, the URL of the avatar is submitted, along with the username and full name of the user, to your desired endpoint for server-side handling.
The JavaScript method, &lt;code&gt;s3_upload()&lt;/code&gt;, is called when a file is selected by the user. The creation and population of this method is covered below.&lt;/p&gt;

&lt;p&gt;Next, include the three dependency scripts in your HTML file, &lt;code&gt;account.html&lt;/code&gt;. You may need to adjust the &lt;code&gt;src&lt;/code&gt; attribute for the file &lt;code&gt;s3upload.js&lt;/code&gt; if you put this file in a directory other than &lt;code&gt;/static&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="html"&gt;&amp;lt;script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type="text/javascript" src="https://raw.github.com/bestiejs/lodash/v1.1.1/dist/lodash.min.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type="text/javascript" src="/static/s3upload.js"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;div class="note"&gt;
&lt;p&gt;The ordering of the scripts is important as the dependencies need to be satisfied in this sequence.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Finally, in a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; block, declare a JavaScript function, &lt;code&gt;s3_upload()&lt;/code&gt;, in the same file again to process the file upload. This &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; block will need to exist below the inclusion of the three dependencies:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;function s3_upload(){
    var s3upload = new S3Upload({
        file_dom_selector: '#file',
        s3_sign_put_url: '/sign_s3_upload/',

        onProgress: function(percent, message) { 
            $('#status').html('Upload progress: ' + percent + '%' + message);
        },
        onFinishS3Put: function(url) { 
            $('#status').html('Upload completed. Uploaded to: '+ url);
            $("#avatar_url").val(public_url);
            $("#preview").html('&amp;lt;img src="'+public_url+'" style="width:300px;" /&amp;gt;');
        },
        onError: function(status) {
            $('#status').html('Upload error: ' + status);
        }
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This function creates a new instance of &lt;code&gt;S3Upload&lt;/code&gt;, to which is passed the file input element, the URL from which to retrieve the signed request and three functions. &lt;/p&gt;

&lt;p&gt;Initially, the function makes a request to the URL denoted by the &lt;code&gt;s3_sign_put_url&lt;/code&gt; argument, passing the file name and mime type as GET parameters. The server-side code (covered in the next section) interprets the request and responds with a preview of the URL of the file to be uploaded to S3 and the signed request, which this function then uses to asynchronously upload the file to your bucket.&lt;/p&gt;

&lt;p&gt;The function will post upload updates to the &lt;code&gt;onProgress()&lt;/code&gt; function and , if the upload is successful, &lt;code&gt;onFinishS3Put()&lt;/code&gt; is called and the URL returned by the Python application view is received as an argument. If, for any reason, the upload should fail, &lt;code&gt;onError()&lt;/code&gt; will be called and the &lt;code&gt;status&lt;/code&gt; parameter will describe the error.&lt;/p&gt;

&lt;div class="warning"&gt;
&lt;p&gt;If you find that the page isn't working as you intend after implementing the system, then consider using &lt;code&gt;console.log()&lt;/code&gt; to record any errors that occur inside the &lt;code&gt;onError()&lt;/code&gt; callback and use your browser's error console to help diagnose the problem.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;If successful, the &lt;code&gt;preview&lt;/code&gt; &lt;code&gt;div&lt;/code&gt; will now be updated with the user's chosen avatar image, and the hidden &lt;code&gt;input&lt;/code&gt; field will contain the URL for the image. Now, once the user has completed the rest of the form and clicked submit, all three pieces of information can be posted to the same endpoint.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;It is good practice to inform the user of any prolonged activity in any form of application (web- or device-based) and to display updates on changes. Thus the status methods could be used, for example, to show a loading GIF to indicate that an upload is in progress, which can then be hidden when the upload has finished.
Without this sort of information, users may suspect that the page has crashed, and could try to refresh the page or otherwise disrupt the upload process.&lt;/p&gt;
&lt;/div&gt;

&lt;h3 id="setting-up-the-server-side-python-code"&gt;Setting up the server-side Python code&lt;/h3&gt;

&lt;p&gt;This section discusses the use of Python for generating a temporary signature with which the upload request can be signed. This temporary signature uses the account details (the AWS access key and secret access key) as a basis for the signature, but users will not have direct access to this information. After the signature has expired, then upload requests with the same signature will not be successful.&lt;/p&gt;

&lt;p&gt;As mentioned previously, this article covers the production of an application for the Flask framework, although the steps for other Python frameworks will be similar.&lt;/p&gt;

&lt;div class="callout"&gt;
&lt;p&gt;To see the completed Python file, please see the appropriate code in the companion &lt;a href="https://github.com/flyingsparx/FlaskDirectUploader/blob/master/application.py"&gt;repository&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Start by creating your main application file, &lt;code&gt;application.py&lt;/code&gt;, and set up your skeleton application appropriately:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;from flask import Flask, render_template, request
import time, os, json, base64, hmac, sha

app = Flask(__name__)

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The currently-unused import statements will be necessary later on.&lt;/p&gt;

&lt;p&gt;Next, in the same file, you will need to create the views responsible for returning the correct information back to the user's browser when requests are made to various URLs. First define view for requests to &lt;code&gt;/account&lt;/code&gt; to return the page &lt;code&gt;account.html&lt;/code&gt;, which contains the form for the user to complete:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;@app.route("/account/")
def account():
    return render_template('account.html')
&lt;/code&gt;&lt;/pre&gt;

&lt;div class="note"&gt;
&lt;p&gt;Please note that the views for the application will need to be placed between the &lt;code&gt;app = Flask(__name__)&lt;/code&gt; and &lt;code&gt;if __name__ == '__main__':&lt;/code&gt; lines in &lt;code&gt;application.py&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Now create the view, in the same Python file,  that is responsible for generating and returning the signature with which the client-side JavaScript can upload the image. This is the first request made by the client before attempting an upload to S3. This view responds with requests to &lt;code&gt;/sign_s3/&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;@app.route('/sign_s3/')
def sign_s3():
    AWS_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY_ID')       
    AWS_SECRET_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
    S3_BUCKET = os.environ.get('S3_BUCKET')

    object_name = request.args.get('s3_object_name')
    mime_type = request.args.get('s3_object_type')

    expires = int(time.time()+10)
    amz_headers = "x-amz-acl:public-read"

    put_request = "PUT\n\n%s\n%d\n%s\n/%s/%s" % (mime_type, expires, amz_headers, S3_BUCKET, object_name)

    signature = base64.encodestring(hmac.new(AWS_SECRET_KEY, put_request, sha).digest())

    url = 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, object_name)

    return json.dumps({
        'signed_request': '%s?AWSAccessKeyId=%s&amp;amp;Expires=%d&amp;amp;Signature=%s' % (url, AWS_ACCESS_KEY, expires, signature),
         'url': url
      })
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code performs the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The request is received to &lt;code&gt;/sign_s3/&lt;/code&gt; and the AWS keys and S3 bucket name are loaded from the environment.&lt;/li&gt;
&lt;li&gt;The name and mime type of the object to be uploaded are extracted from the &lt;code&gt;GET&lt;/code&gt; parameters of the request (this stage may differ in other frameworks). The parameters are provided by the JavaScript discussed in the previous section.&lt;/li&gt;
&lt;li&gt;The expiry time of the signature is set and forms the basis of the temporary nature of the signature. As shown, this is best used as a function relative to the current UNIX time. In this example, the signature will expire 10 seconds after Python has executed that line of code.&lt;/li&gt;
&lt;li&gt;The headers line tells S3 what access permissions to grant. In this case, the object will be publicly available for download.&lt;/li&gt;
&lt;li&gt;Now the &lt;code&gt;PUT&lt;/code&gt; request can be constructed from the object information, headers and expiry time.&lt;/li&gt;
&lt;li&gt;The signature is generated as an SHA hash of the compiled AWS secret key and the actual &lt;code&gt;PUT&lt;/code&gt; request.&lt;/li&gt;
&lt;li&gt;The prospective URL of the object to be uploaded is produced as a combination of the S3 bucket name and the object name.&lt;/li&gt;
&lt;li&gt;Finally, the signed request can be returned, along with the prospective URL, to the browser in JSON format.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;You may wish to assign another, customised name to the object instead of using the one that the file is already named with, which is useful for preventing accidental overwrites in the S3 bucket. This name could be related to the ID of the user’s account, for example. If not, you should provide some method for properly quoting the name in case there are spaces or other awkward characters present. In addition, this is the stage at which you could provide checks on the uploaded file in order to restrict access to certain file types. For example, a simple check could be implemented to allow only &lt;code&gt;.png&lt;/code&gt; files to proceed beyond this point.&lt;/p&gt;

&lt;div class="warning"&gt;
&lt;p&gt;It is sometimes possible for S3 to respond with 403 (forbidden) errors for requests which aren't formatted correctly. If this happens then it may be necessary to quote the signature and remove any whitespace. The &lt;a href="http://docs.python.org/2/library/urllib.html"&gt;urllib&lt;/a&gt; module and string &lt;code&gt;strip()&lt;/code&gt; methods can be used to achieve this.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Finally, in &lt;code&gt;application.py&lt;/code&gt;, create the view responsible for receiving the account information after the user has uploaded an avatar, filled in the form, and clicked submit. Since this will be a &lt;code&gt;POST&lt;/code&gt; request, this will also need to be defined as an ‘allowed access method’. This method will respond to requests to the URL &lt;code&gt;/submit_form/&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;@app.route("/submit_form/", methods=["POST"])
def submit_form():
    username = request.form["username"]
    full_name = request.form["full_name"]
    avatar_url = request.form["avatar_url"]
    update_account(username, full_name, avatar_url)
    return redirect(url_for('profile'))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, an &lt;code&gt;update_account()&lt;/code&gt; function has been called, but creation of this method is not covered in this article. In your application, you should provide some functionality, at this stage, to allow the app to store these account details in some form of database and correctly associate the information with the rest of the user’s account details.&lt;/p&gt;

&lt;p&gt;In addition, the URL for the profile page has not been defined in this article (or companion code). Ideally, for example, after updating the account, the user would be redirected back to their own profile so that they can see the updated information.&lt;/p&gt;

&lt;h2 id="running-the-app"&gt;Running the app&lt;/h2&gt;

&lt;p&gt;Everything should now be in place to perform the direct uploads to S3. To test the upload, save any changes and use &lt;code&gt;foreman&lt;/code&gt; to start the application:&lt;/p&gt;

&lt;div class="callout"&gt;
&lt;p&gt;You will need a Procfile for this to be successful. See &lt;a href="https://devcenter.heroku.com/python"&gt;Getting Started with Python on Heroku&lt;/a&gt; for information on the Heroku toolbelt and using Foreman. Also remember to correctly set your environment variables on your own machine before running the application locally.&lt;/p&gt;
&lt;/div&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ foreman start
15:44:36 web.1  | started with pid 12417
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Press &lt;code&gt;Ctl-C&lt;/code&gt; to return to the prompt. If your application is returning &lt;code&gt;500&lt;/code&gt; errors (or other server-based issues), then start your server in debug mode and view the output in the Terminal emulator to help fix your problem. For example, in Flask:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;...
app.debug = True
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
&lt;/code&gt;&lt;/pre&gt;

&lt;div class="warning"&gt;
&lt;p&gt;If you are receiving 403 errors back from S3, then the most common reason is that there is an issue with your signature. As mentioned earlier, you should consider quoting the signature properly and removing any whitespace.&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;

&lt;p&gt;This article covers uploading to Amazon S3 directly from the browser using Python to temporarily sign the upload request. Although the guide and companion code focuses on the Flask framework, the idea should easily carry over to other Python applications.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/d1vpQU51UOs" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/s3-upload-python</feedburner:origLink></entry>
  <entry>
    <id>tag:devcenter.heroku.com,2005:Article/1647</id>
    <published>2013-05-07T00:39:44Z</published>
    <updated>2013-05-21T20:19:49Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/5H0nJmoNYpI/pentest-instructions" />
    <title>Penetration Testing and Network Scanning</title>
    <content type="html">&lt;p&gt;Coordinated penetration tests and network security scans are allowed on Heroku.&lt;/p&gt;

&lt;h2 id="planning"&gt;Planning&lt;/h2&gt;

&lt;p&gt;Since overaggressive scans are hard to distinguish from Denial of Service attacks, please &lt;a href="https://help.heroku.com/tickets/new?q=devcenter+referral+pentest+instructions"&gt;notify Heroku in advance of all automated security scans&lt;/a&gt; and provide the following information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Approximate date and time window you’ll be conducting the test (e.g., “between 8am-noon US/Pacific time, 18 September 2012”). Multiple windows are fine.&lt;/li&gt;

&lt;li&gt;Source IP address range you’ll be using.&lt;/li&gt;

&lt;li&gt;Which specific applications, hostnames, and URLs you’ll be testing.&lt;/li&gt;

&lt;li&gt;Contact information, including a phone number, for the individual or team conducting the test.&lt;/li&gt;
&lt;/ul&gt;&lt;h2 id="scanning"&gt;Scanning&lt;/h2&gt;

&lt;p&gt;We also ask the following of your penetration tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide updates at the start and end of each test. It’s OK if it slips a couple of hours.&lt;/li&gt;

&lt;li&gt;Rate limit HTTP requests to no more than 250 requests per second, summing together across all tools and source IPs. If you need to go above that you may need to be assigned a specific testing time window.&lt;/li&gt;

&lt;li&gt;If you find any vulnerabilities in our platform or any add-on services, please treat them as confidential and notify us at &lt;a href="mailto:security@heroku.com"&gt;security@heroku.com&lt;/a&gt; at once. If it’s particularly serious, the Heroku Security Team’s PGP key &lt;a href="https://policy.heroku.com/security#vuln_report"&gt;is here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/5H0nJmoNYpI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/pentest-instructions</feedburner:origLink></entry>
  <entry>
    <id>tag:devcenter.heroku.com,2005:Article/1644</id>
    <published>2013-05-06T14:57:04Z</published>
    <updated>2013-05-08T09:08:10Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/PjAEN7VZuLI/heroku-postgres-metrics-logs" />
    <title>Heroku Postgres Metrics Logs</title>
    <content type="html">&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;

&lt;p&gt;Heroku Postgres &lt;a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#production-tier"&gt;Production Tier database&lt;/a&gt; users will see database
related events on their app's stream. This can be useful for
recording and analyzing usage over time.&lt;/p&gt;

&lt;h2 id="log-format"&gt;Log format&lt;/h2&gt;

&lt;pre&gt;&lt;code class="term"&gt;2013-05-07T17:41:06+00:00 source=HEROKU_POSTGRESQL_VIOLET measure.current_transaction=1873 measure.db_size=26219348792bytes measure.tables=13 measure.active-connections=92 measure.waiting-connections=1 measure.index-cache-hit-rate=0.99723 measure.table-cache-hit-rate=0.99118
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The attributes found on the log are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;measure.db_size&lt;/code&gt;: The number of bytes contained in the database. This includes all
table and index data on disk, including database bloat.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;measure.tables&lt;/code&gt;: The number of tables in the database.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;measure.active-connections&lt;/code&gt;: The number of &lt;a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#production-tier"&gt;connections&lt;/a&gt; established on the database.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;measure.current_transaction&lt;/code&gt;: The current transaction ID, which can be used to track writes over time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;measure.index-cache-hit-rate&lt;/code&gt;: Rate of index lookups served from &lt;a href="https://devcenter.heroku.com/articles/understanding-postgres-data-caching"&gt;shared buffer cache&lt;/a&gt;, rounded to five decimal points.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;measure.table-cache-hit-rate&lt;/code&gt;: Rate of table lookups served from &lt;a href="https://devcenter.heroku.com/articles/understanding-postgres-data-caching"&gt;shared buffer cache&lt;/a&gt;, rounded to five decimal points.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;measure.waiting-connections&lt;/code&gt;: Number of connections waiting on a lock to be acquired.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;source&lt;/code&gt;: The database name the measurements relate to.&lt;/li&gt;
&lt;li&gt;The log line's timestamp is the time at which the measurements were taken.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/PjAEN7VZuLI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/heroku-postgres-metrics-logs</feedburner:origLink></entry>
  <entry>
    <id>tag:devcenter.heroku.com,2005:Article/959</id>
    <published>2013-05-01T20:59:37Z</published>
    <updated>2013-05-22T09:18:25Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/16i3YMLFpds/how-heroku-works" />
    <title>How Heroku Works</title>
    <content type="html">&lt;p&gt;This is a high-level, technical description of how Heroku works.  It ties together many of the concepts you'll encounter while writing, configuring, deploying and running applications on the Heroku platform. &lt;/p&gt;

&lt;div class="callout"&gt;
&lt;p&gt;Performing one of the &lt;a href="https://devcenter.heroku.com/quickstart"&gt;Getting Started&lt;/a&gt; tutorials 
will make the concepts in this documentation more concrete.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Read this document sequentially: in order to tell a coherent story, it incrementally unveils and refines the concepts describing the platform.  &lt;/p&gt;

&lt;p&gt;The final section ties all the definitions together, providing a &lt;a href="#deploy"&gt;deploy-time&lt;/a&gt; and &lt;a href="#runtime"&gt;runtime-view&lt;/a&gt; of Heroku. &lt;/p&gt;

&lt;h2 id="defining-an-application"&gt;Defining an application&lt;/h2&gt;

&lt;p&gt;Heroku lets you deploy, run and manage applications written in Ruby, Node.js, Java, Python, Clojure and Scala.  &lt;/p&gt;

&lt;p&gt;An application is a collection of &lt;em&gt;source code&lt;/em&gt; written in one of these languages, perhaps a framework, and some &lt;em&gt;dependency description&lt;/em&gt; that instructs a build system as to which additional dependencies are needed in order to build and run the application.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt; (Preliminary): Applications consist of your source code and a description of any dependencies.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Dependency mechanisms vary across languages: in Ruby you use a &lt;code&gt;Gemfile&lt;/code&gt;, in Java a &lt;code&gt;pom.xml&lt;/code&gt;, in Python a &lt;code&gt;requirements.txt&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;The source code for your application, together with the dependency file, should provide enough information for the Heroku platform to build your application, to produce something that can be executed.&lt;/p&gt;

&lt;h2 id="knowing-what-to-execute"&gt;Knowing what to execute&lt;/h2&gt;

&lt;p&gt;You don't need to make many changes to an application in order to run it on Heroku. One requirement is informing the platform as to which parts of your application are runnable.&lt;/p&gt;

&lt;p&gt;If you're using some established framework, Heroku can figure it out.  For example, in Ruby on Rails, it's typically &lt;code&gt;rails server&lt;/code&gt;, in Django it's &lt;code&gt;python &amp;lt;app&amp;gt;/manage.py runserver&lt;/code&gt; and in Node.js it's &lt;code&gt;node web.js&lt;/code&gt;.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: &lt;a href="https://devcenter.heroku.com/procfile"&gt;Procfiles&lt;/a&gt; list process types - named commands that you may want executed.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;For other applications, you may need to explicitly declare what can be executed.  You do this in a text file that accompanies your source code - a &lt;a href="https://devcenter.heroku.com/procfile"&gt;Procfile&lt;/a&gt;.  Each line declares a &lt;a href="https://devcenter.heroku.com/process-model"&gt;process type&lt;/a&gt; - a named command that can be executed against your built application.  For example, your Procfile may look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;web: java -jar lib/foobar.jar $PORT
queuty: java -jar lib/queue-processor.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This file declares a &lt;code&gt;web&lt;/code&gt; process type and provides the command that needs to be executed in order to run it (in this case, &lt;code&gt;java -jar lib/foobar.jar $PORT&lt;/code&gt;).  It also declares a &lt;code&gt;queuty&lt;/code&gt; process type, and its corresponding command.&lt;/p&gt;

&lt;p&gt;The earlier definition of an application can now be refined to include this single additional Procfile.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: Applications consist of your source code, a description of any dependencies, and a Procfile.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Heroku is a polyglot platform -- it lets you build, run and scale applications in a similar manner across all the languages -- utilizing the dependencies and Procfile.  The Procfile exposes an architectural aspect of your application (in the above example there are two entry points to the application) and this architecture lets you, for example, scale each part independently.  An excellent guide to architecture principals that work well for applications running on Heroku can be found in &lt;a href="http://www.12factor.net"&gt;The Twelve-Factor App&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="deploying-applications"&gt;Deploying applications&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt; is a powerful, distributed version control system that many developers use to manage and version source code.  The Heroku platform uses git as the primary means for deploying applications. &lt;/p&gt;

&lt;p&gt;When you create an application on Heroku, it associates a new git remote, typically named &lt;code&gt;heroku&lt;/code&gt;, with the local git repository for your application.  &lt;/p&gt;

&lt;p&gt;As a result, deploying code is just the familiar &lt;code&gt;git push&lt;/code&gt;, but to the &lt;code&gt;heroku&lt;/code&gt; remote instead:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ git push heroku master
&lt;/code&gt;&lt;/pre&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: Deploying applications involves sending the application to Heroku using git.  &lt;/p&gt;
&lt;/div&gt;

&lt;!--&lt;p class="warning"&gt;So deploying an application to Heroku is about pushing a branch of your local git repository (which represents your source code) to Heroku. If you make local changes and don't add them to your git repository then pushing will be futile - you haven't actually pushed the changes at all.  You have to add and commit those changes to your local repository first.&lt;/p&gt;--&gt;

&lt;p&gt;Deployment then, is about using git as a transport mechanism - moving your application from your local system to Heroku.&lt;/p&gt;

&lt;h2 id="building-applications"&gt;Building applications&lt;/h2&gt;

&lt;p&gt;When the Heroku platform receives a git push, it initiates a build of the source application.  The build mechanism is typically language specific, but follows the same pattern, typically retrieving the specified dependencies, and creating any necessary assets (whether as simple as processing style sheets or as complex as compiling code).  &lt;/p&gt;

&lt;div class="callout"&gt;
&lt;p&gt;&lt;strong&gt;Advanced&lt;/strong&gt;: &lt;a href="https://devcenter.heroku.com/buildpacks"&gt;Buildpacks&lt;/a&gt; lie behind the slug compilation process.  They're open source - enabling you to extend Heroku to other languages and frameworks.  Buildpacks take your application, its dependencies, and the language runtime, and produce slugs.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;For example, when the build system receives a Rails application, it may fetch all the dependencies specified in the Gemfile, as well as generate files based on the asset pipeline.  A Java application may fetch binary library dependencies using Maven, compile the source code together with those libraries, and produce a JAR file to execute.&lt;/p&gt;

&lt;p&gt;The source code for your application, together with the fetched dependencies and output of the build phase such as generated assets or compiled code, as well as the language and framework, are assembled into a &lt;a href="https://devcenter.heroku.com/slug-compiler"&gt;slug&lt;/a&gt;.  &lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: A &lt;a href="https://devcenter.heroku.com/slug-compiler"&gt;slug&lt;/a&gt; is a bundle of your source, fetched dependencies, the language runtime, and compiled/generated output of the build system - ready for execution.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;These slugs are a fundamental aspect of what happens during application execution - they contain your compiled, assembled application - ready to run - together with the instructions (the Procfile) of what you may want to execute.&lt;/p&gt;

&lt;h2 id="running-applications-on-dynos"&gt;Running applications on dynos&lt;/h2&gt;

&lt;p&gt;Heroku executes applications by running a command you specified in the Procfile, on a &lt;a href="https://devcenter.heroku.com/dynos"&gt;dyno&lt;/a&gt; that's been preloaded with your prepared slug (in fact, with your release, which extends your slug and a few items not yet defined: config vars and add-ons).  &lt;/p&gt;

&lt;p&gt;Think of a running dyno as a lightweight, secure, virtualized Unix container that contains your application slug in its file system. &lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: &lt;a href="https://devcenter.heroku.com/dynos"&gt;Dynos&lt;/a&gt; are isolated, virtualized Unix containers, that provide the environment required to run an application. &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Generally, if you deploy an application for the first time, Heroku will run 1 web dyno automatically.  In other words, it will boot a dyno, load it with your slug, and execute the command you've associated with the web process type in your Procfile. &lt;/p&gt;

&lt;p&gt;You have control over how many dynos are running at any given time.  Given the Procfile example earlier, you can start 5 dynos, 3 for the web and 2 for the queuety process types, as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku ps:scale web=3 queuty=2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you deploy a new version of an application, all of the currently executing dynos are killed, and new ones (with the new release) are started to replace them - preserving the existing dyno formation. &lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: Your application's &lt;a href="https://devcenter.heroku.com/scaling#dyno-formation"&gt;dyno formation&lt;/a&gt; is the total number of currently-executing dynos, divided between the various process types you have scaled.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;To understand what's executing, you just need to know what dynos are running which process types:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku ps
== web: 'java lib/foobar.jar $PORT'
web.1: up 2013/02/07 18:59:17 (~ 13m ago)
web.1: up 2013/02/07 18:52:08 (~ 20m ago)
web.2: up 2013/02/07 18:31:14 (~ 41m ago)

== queuty: `java lib/queue-processor.jar` 
queuty.1: up 2013/02/07 18:40:48 (~ 32m ago)
queuty.2: up 2013/02/07 18:40:48 (~ 32m ago)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Dynos then, are an important means of scaling your application.  In this example, the application is well architected to allow for the independent scaling of web and queue worker dynos.&lt;/p&gt;

&lt;h2 id="config-vars"&gt;Config vars&lt;/h2&gt;

&lt;p&gt;An application’s configuration is everything that is likely to vary between deploys (staging, production, developer environments, etc.). This includes resource handles to backing services such as databases, credentials, or environment variables that provide some contextual information to your application.&lt;/p&gt;

&lt;p&gt;Heroku lets you run your application with a customizable configuration - the configuration sits outside of your application code and can be changed independently of it.&lt;/p&gt;

&lt;p&gt;The configuration for an application is stored in &lt;a href="https://devcenter.heroku.com/config-vars"&gt;config vars&lt;/a&gt;.  For example, here's how to configure an encryption key for an application:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku config:add ENCRYPTION_KEY=my_bad_ass_long_random_key 
Adding config vars and restarting demoapp... done, v14
ENCRYPTION_KEY:     my_bad_ass_long_random_key 
&lt;/code&gt;&lt;/pre&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: &lt;a href="https://devcenter.heroku.com/config-vars"&gt;Config vars&lt;/a&gt; contain customizable configuration data that can be changed independently of your source code. The configuration is exposed to a running application via environment variables.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;At runtime, all of the config vars are exposed as environment variables - so they can be easily extracted programatically.  A Ruby application deployed with the above config var, can access it by calling &lt;code&gt;ENV["ENCRYPTION_KEY"]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All dynos in an application will have access to the exact same set of config vars at runtime.  &lt;/p&gt;

&lt;h2 id="releases"&gt;Releases&lt;/h2&gt;

&lt;p&gt;Earlier, this article stated that to run your application on a dyno, the Heroku platform loaded the dyno with your most recent slug.  This needs to be refined: in fact it loads it with the slug and any config variables you have assigned to the application.  The combination of slug and configuration is called a &lt;a href="https://devcenter.heroku.com/releases"&gt;release&lt;/a&gt;.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt; (Preliminary): &lt;a href="https://devcenter.heroku.com/releases"&gt;Releases&lt;/a&gt; are an append-only ledger of slugs and config vars.  &lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;All releases are automatically persisted in an append-only ledger, making managing your application, and different releases, a cinch. Use the &lt;code&gt;heroku releases&lt;/code&gt; command to see the audit trail of release deploys:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku releases
== demoapp Releases
v103 Deploy 582fc95  jon@heroku.com   2013/01/31 12:15:35
v102 Deploy 990d916  jon@heroku.com   2013/01/31 12:01:12
&lt;/code&gt;&lt;/pre&gt;

&lt;div class="callout"&gt;
&lt;p&gt;The number next to the deploy message, for example &lt;code&gt;582fc95&lt;/code&gt;, corresponds to the commit hash of the repository you deployed to Heroku.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Every time you deploy a new version of an application, a new slug is created and release is generated.&lt;/p&gt;

&lt;p&gt;As Heroku contains a store of the previous releases of your application, it's very easy to rollback and deploy a previous release:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku releases:rollback v102
Rolling back demoapp... done, v102
$ heroku releases
== demoapp Releases
v104 Rollback to v102 jon@heroku.com   2013/01/31 14:11:33 (~15s ago)
v103 Deploy 582fc95   jon@heroku.com   2013/01/31 12:15:35
v102 Deploy 990d916   jon@heroku.com   2013/01/31 12:01:12
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Making a material change to your application, whether it's changing the source or configuration, results in a new release being created.  &lt;/p&gt;

&lt;p&gt;A release then, is the mechanism behind how Heroku lets you modify the configuration of your application (the config vars) independently of the application source (stored in the slug) - the release binds them together.  Whenever you change a set of config vars associated with your application, a new release will be generated.&lt;/p&gt;

&lt;h2 id="dyno-manager"&gt;Dyno manager&lt;/h2&gt;

&lt;p&gt;Part of the Heroku platform, the &lt;a href="https://devcenter.heroku.com/dynos"&gt;dyno manager&lt;/a&gt;, is responsible for keeping dynos running.  For example, dynos are cycled at least once per day, or whenever the dyno manager detects a fault in the running application (such as out of memory exceptions) or problems with the underlying hardware that requires the dyno be moved to a new physical location. &lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: The &lt;a href="https://devcenter.heroku.com/dynos"&gt;dyno manager&lt;/a&gt; of the Heroku platform is responsible for managing dynos across all applications running on Heroku.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;This dyno cycling happens transparently and automatically on a regular basis, and is logged. &lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: Applications with only a single web dyno are &lt;a href="https://devcenter.heroku.com/dynos#dyno-idling"&gt;idled&lt;/a&gt; after a period of inactivity. When an idled application receives HTTP traffic, it will be unidled - causing a delay of a few seconds.
Scaling the web dynos will avoid idling.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Because Heroku manages and runs applications, there's no need to manage operating systems or other internal system configuration.  &lt;a href="https://devcenter.heroku.com/one-off-dynos"&gt;One-off dynos&lt;/a&gt; can be run with their input/output attached to your local terminal.  These can also be used to carry out admin tasks that modify the state of shared resources - for example, database configuration.  &lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: &lt;a href="https://devcenter.heroku.com/one-off-dynos"&gt;One-off Dynos&lt;/a&gt; are temporary dynos that can run with their input/output attached to your local terminal.  They're loaded with your latest release.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Here's the simplest way to create and attach to a one-off dyno:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku run bash
Running `bash` attached to terminal... up, run.8963
~ $ ls
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will spin up a new dyno, loaded with your release, and then run the &lt;code&gt;bash&lt;/code&gt; command - which will provide you with a unix shell (remember that dynos are effectively isolated virtualized unix containers).   Once you've terminated your session, or after a period of inactivty, the dyno will be removed.&lt;/p&gt;

&lt;p&gt;Changes to the filesystem on one dyno are not propagated to other dynos and are not persisted across deploys and dyno restarts.  A better and more scalable approach is to use a shared resource such as a database or queue.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: Each dyno gets its own &lt;a href="https://devcenter.heroku.com/dynos#ephemeral-filesystem"&gt;ephemeral filesystem&lt;/a&gt; - with a fresh copy of the most recent release. It can be used as temporary scratchpad, but changes to the filesystem are not reflected to other dynos.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The ephemeral nature of the file system in a dyno can be demonstrated with the above command.  If you create a one-off dyno by running &lt;code&gt;heroku run bash&lt;/code&gt;, the Unix shell on the dyno, and then create a file on that dyno, and then terminate your session - the change is lost.  All dynos, even those in the same application, are isolated - and after the session is terminated the dyno will be killed. New dynos are always created from a slug, not from the state of other dynos. &lt;/p&gt;

&lt;h2 id="add-ons"&gt;Add-ons&lt;/h2&gt;

&lt;p&gt;Applications typically make use of add-ons to provide backing services such as databases, queueing &amp;amp; caching systems, storage, email services and more.  Add-ons are provided as services by Heroku and third parties - there's a large &lt;a href="https://addons.heroku.com/"&gt;marketplace&lt;/a&gt; of add-ons you can choose from.&lt;/p&gt;

&lt;p&gt;Heroku treats these add-ons as attached resources: provisioning an add-on is a matter of choosing one from the add-on marketplace, and attaching it to your application.  &lt;/p&gt;

&lt;p&gt;For example, here is how to add a Redis backing store add-on (by &lt;a href="https://devcenter.heroku.com/articles/redistogo#provisioning-the-addon"&gt;RedisToGo&lt;/a&gt;) to an application:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:add redistogo:nano
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The add-on service provider is responsible for the service - and the interface to your application is often provided through a config var. In this example, a &lt;code&gt;REDISTOGO_URL&lt;/code&gt; will be automatically added to your application when you provision the add-on.  You can write code that connects to the service through the URL, for example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="ruby"&gt;uri = URI.parse(ENV["REDISTOGO_URL"])
REDIS = Redis.new(:host =&amp;gt; uri.host, :port =&amp;gt; uri.port, :password =&amp;gt; uri.password)
&lt;/code&gt;&lt;/pre&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: &lt;a href="https://addons.heroku.com/"&gt;Add-ons&lt;/a&gt; are third party, specialized, value-added cloud services that can be easily attached to an application, extending its functionality.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Add-ons are associated with an application, much like config vars - and so the earlier definition of a release needs to be refined.  A &lt;em&gt;release&lt;/em&gt; of your applications is not just your slug and config vars; it's your slug, config vars as well as the set of provisioned add-ons. &lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: &lt;a href="https://devcenter.heroku.com/releases"&gt;Releases&lt;/a&gt; are an append-only ledger of slugs, config vars and add-ons.  Heroku maintains an append-only ledger of releases you make.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Much like config vars, whenever you add, remove or change an add-on, a new release is created. &lt;/p&gt;

&lt;h2 id="logging-and-monitoring"&gt;Logging and monitoring&lt;/h2&gt;

&lt;p&gt;Heroku treats logs as streams of time-ordered events, and collates the stream of logs produced from all of the processes running in all dynos, and the Heroku platform components, into the &lt;a href="https://devcenter.heroku.com/logplex"&gt;Logplex&lt;/a&gt; - a high-performance, real-time system for log delivery.&lt;/p&gt;

&lt;p&gt;It's easy to examine the logs across all the platform components and dynos:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku logs
2013-02-11T15:19:10+00:00 heroku[router]: at=info method=GET path=/articles/custom-domains host=mydemoapp.heroku.com fwd=74.58.173.188 dyno=web.1 queue=0 wait=0ms connect=0ms service=1452ms status=200 bytes=5783
2013-02-11T15:19:10+00:00 app[web.2]: Started GET "/" for 1.169.38.175 at 2013-02-11 15:19:10 +0000
2013-02-11T15:19:10+00:00 app[web.1]: Started GET "/" for 2.161.132.15 at 2013-02-11 15:20:10 +0000
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here you see 3 timestamped log entries, the first from Heroku's router, the last two from two dynos running the web process type.&lt;/p&gt;

&lt;div class="note"&gt;
&lt;p&gt;&lt;strong&gt;Terminology&lt;/strong&gt;: &lt;a href="https://devcenter.heroku.com/logplex"&gt;Logplex&lt;/a&gt; automatically collates log entries from all the running dynos of  your app, as well as other components such as the routers, providing a single source of activity.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;You can also dive into the logs from just a single dyno, and keep the channel open, listening for further events:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku logs --ps web.1 --tail
2013-02-11T15:19:10+00:00 app[web.2]: Started GET "/" for 1.169.38.175 at 2013-02-11 15:19:10 +0000
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Logplex keeps a limited buffer of log entries solely for performance reasons.  To persist them, and action events such as email notification on exception, use a &lt;a href="https://addons.heroku.com/#logging"&gt;Logging Add-on&lt;/a&gt;, which ties into log drains - an API for receiving the output from Logplex.&lt;/p&gt;

&lt;h2 id="http-routing"&gt;HTTP routing&lt;/h2&gt;

&lt;p&gt;Depending on your dyno formation, some of your dynos will be running the command associated with the &lt;code&gt;web&lt;/code&gt; process type, and some will be running other commands associated with other process types.&lt;/p&gt;

&lt;p&gt;The dynos that run process types named &lt;code&gt;web&lt;/code&gt; are different in one way from all other dynos - they will receive HTTP traffic.  Heroku's &lt;a href="https://devcenter.heroku.com/http-routing"&gt;HTTP routers&lt;/a&gt; distributes incoming requests for your application across your running web dynos.&lt;/p&gt;

&lt;p&gt;So scaling an app's capacity to handle web traffic involves scaling the number of web dynos:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku ps:scale web+5
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A random selection algorithm is used for HTTP request load balancing across web dynos - and this routing handles both HTTP and HTTPS traffic.  It also supports multiple simultaneous connections, as well as timeout handling.&lt;/p&gt;

&lt;h2 id="tying-it-all-together"&gt;Tying it all together&lt;/h2&gt;

&lt;p&gt;The concepts explained here can be divided into two buckets: those that involve the development and deployment of an application, and those that involve the runtime operation of the Heroku platform and the application after its deployed.&lt;/p&gt;

&lt;p&gt;The following two sections recapitulate the main components of the platform, separating them into these two buckets.&lt;/p&gt;

&lt;h3 id="deploy"&gt;Deploy&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Applications consist of your source code, a description of any dependencies, and a Procfile.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devcenter.heroku.com/procfile"&gt;Procfiles&lt;/a&gt; list process types - named commands that you may want executed.&lt;/li&gt;
&lt;li&gt;Deploying applications involves sending the application to Heroku using git.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devcenter.heroku.com/buildpacks"&gt;Buildpacks&lt;/a&gt; lie behind the slug compilation process. Buildpacks take your application, its dependencies, and the language runtime, and produce slugs.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://devcenter.heroku.com/slug-compiler"&gt;slug&lt;/a&gt; is a bundle of your source, fetched dependencies, the language runtime, and compiled/generated output of the build system - ready for execution.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devcenter.heroku.com/config-vars"&gt;Config vars&lt;/a&gt; contain customizable configuration data that can be changed independently of your source code. The configuration is exposed to a running application via environment variables.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://addons.heroku.com/"&gt;Add-ons&lt;/a&gt; are third party, specialized, value-added cloud services that can be easily attached to an application, extending its functionality.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://devcenter.heroku.com/releases"&gt;release&lt;/a&gt; is a combination of a slug (your application), config vars and add-ons.  Heroku maintains an append-only ledger of releases you make.&lt;/li&gt;
&lt;/ul&gt;&lt;h3 id="runtime"&gt;Runtime&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://devcenter.heroku.com/dynos"&gt;Dynos&lt;/a&gt; are isolated, virtualized unix containers, that provide the environment required to run an application.&lt;/li&gt;
&lt;li&gt;Your application's &lt;a href="https://devcenter.heroku.com/scaling#dyno-formation"&gt;dyno formation&lt;/a&gt; is the total number of currently-executing dynos, divided between the various process types you have scaled.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://devcenter.heroku.com/dynos"&gt;dyno manager&lt;/a&gt; is responsible for managing dynos across all applications running on Heroku.&lt;/li&gt;
&lt;li&gt;Applications with only a single web dyno are &lt;a href="https://devcenter.heroku.com/dynos#dyno-idling"&gt;idled&lt;/a&gt; after a period of inactivity by the dyno manager. Scaling to multiple web dynos will avoid this.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devcenter.heroku.com/one-off-dynos"&gt;One-off Dynos&lt;/a&gt; are temporary dynos that run with their input/output attached to your local terminal. They’re loaded with your latest release.&lt;/li&gt;
&lt;li&gt;Each dyno gets its own &lt;a href="https://devcenter.heroku.com/dynos#ephemeral-filesystem"&gt;ephemeral filesystem&lt;/a&gt; - with a fresh copy of the most recent release. It can be used as temporary scratchpad, but changes to the filesystem are not reflected to other dynos.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devcenter.heroku.com/logplex"&gt;Logplex&lt;/a&gt; automatically collates log entries from all the running dynos of  your app, as well as other components such as the routers, providing a single source of activity.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devcenter.heroku.com/scaling"&gt;Scaling&lt;/a&gt; scaling an application involves varying the number of dynos of each process type.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/16i3YMLFpds" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/how-heroku-works</feedburner:origLink></entry>
  <entry>
    <id>tag:devcenter.heroku.com,2005:Article/1591</id>
    <published>2013-05-01T01:11:33Z</published>
    <updated>2013-05-01T09:15:27Z</updated>
    <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/herokudevcenterarticles/~3/u9Vl2slkZnc/migrating-from-postgis-1-5-to-postgis-2-0" />
    <title>Migrating From PostGIS 1.5 to PostGIS 2.0</title>
    <content type="html">&lt;p&gt;PostGIS 2.0 is now available in public beta to Heroku Postgres customers on
production tier plans (Crane and up).  It brings improved stability and features to spatial applications.&lt;/p&gt;

&lt;h2 id="installation"&gt;Installation&lt;/h2&gt;

&lt;p&gt;Unlike PostGIS 1.5, it is available as a Postgres extension on Postgres 9.2 databases. 
To install PostGIS in your database, run the following from a &lt;code&gt;psql&lt;/code&gt; console:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CREATE EXTENSION postgis;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="postgis-1-5-to-2-0-migration"&gt;PostGIS 1.5 to 2.0 Migration&lt;/h2&gt;

&lt;p&gt;To migrate an old Heroku Postgres database running PostGIS 1.5 to the new
architecture, please follow these steps:&lt;/p&gt;

&lt;h3 id="create-a-target-database"&gt;Create a target database&lt;/h3&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:add heroku-postgresql:ronin --version=9.2 --app your-app
Adding heroku-postgresql:ronin on hgmnz... done, v29 ($200/mo)
Attached as HEROKU_POSTGRESQL_LAVANDA_URL
The database should be available in 3-5 minutes.
 ! The database will be empty. If upgrading, you can transfer
 ! data from another database with pgbackups:restore.
Use `heroku pg:wait` to track status..
Use `heroku addons:docs heroku-postgresql:ronin` to view documentation.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="create-the-postgis-extension-on-the-new-database"&gt;Create the postgis extension on the new database&lt;/h3&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku pg:psql LAVANDA --app your-app
&amp;gt; CREATE EXTENSION postgis;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="transfer-your-data-to-a-new-postgres-database"&gt;Transfer your data to a new Postgres database&lt;/h3&gt;

&lt;p&gt;The fastest way to do this is to use the pgbackups:transfer command available
from the &lt;a href="https://github.com/heroku/heroku-pg-extras"&gt;heroku pg-extras&lt;/a&gt; plugin.&lt;/p&gt;

&lt;p&gt;Install the plugin via&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku plugins:install git://github.com/heroku/heroku-pg-extras.git
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This command requires the pgbackups addon. If you don't already have it installed
on your app, install it now:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:add pgbackups --app your-app
Adding pgbackups on hgmnz... done, v32 (free)
You can now use "pgbackups" to backup your databases or import an external backup.
Use `heroku addons:docs pgbackups` to view documentation.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Place your application in maintenance mode, and scale down any workers:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku maintenance:on --app your-app
$ heroku ps:scale worker=0 another_worker=0 --app your-app
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, transfer data from your old database to your new one:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku pgbackups:transfer &amp;lt;OLD_DATABASE_COLOR&amp;gt; LAVANDA --app your-app
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Depending on your data size, the transfer may take a while. You can track
progress of the transfer by tailing your application logs from another shell
window:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku logs --tail -p pbackups --app your-app
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="verify-data-and-promote-your-new-database"&gt;Verify data and promote your new database&lt;/h3&gt;

&lt;p&gt;You can now gain a connection to your new database and run queries verifying
that your data looks as expected. You can also point a staging application to
it to verify that your it works well with Postgis 2.0.&lt;/p&gt;

&lt;p&gt;After you're ready to use the Postgis 2.0 database as the primary for your
application, simply promote it:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku pg:promote HEROKU_POSTGRESQL_LAVANDA --app your-app
Promoting HEROKU_POSTGRESQL_LAVANDA_URL to DATABASE_URL... done
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now that the new database is up and running, scale it back up:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku maintenance:off --app your-app
$ heroku ps:scale worker=4 another_worker=2 --app your-app
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="remove-old-database"&gt;Remove old database&lt;/h3&gt;

&lt;p&gt;Once your new database has been migrated and promoted, you can safely remove
your old one:&lt;/p&gt;

&lt;pre&gt;&lt;code class="term"&gt;$ heroku addons:remove HEROKU_POSTGRESQL_&amp;lt;OLD_DATABASE_COLOR&amp;gt; --app your-app
&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/herokudevcenterarticles/~4/u9Vl2slkZnc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://devcenter.heroku.com/articles/migrating-from-postgis-1-5-to-postgis-2-0</feedburner:origLink></entry>
</feed>
