tag:devcenter.heroku.com,2005:/articles/feedHeroku Dev Center ArticlesHeroku2024-03-12T19:34:10Ztag:devcenter.heroku.com,2005:Article/80782024-03-12T19:34:10Z2024-03-13T09:17:05ZOptimizing Python Application Concurrency<p>Web applications that process incoming HTTP requests concurrently make more efficient use of dyno resources than web applications that only process one request at a time. We recommend using web servers that support concurrent request processing for developing and running production services.</p>
<p>The Django and Flask web frameworks feature convenient built-in web servers, but these blocking servers only process a single request at a time. If you deploy with one of these servers on Heroku, your dyno resources is underutilized and your application feels unresponsive.</p>
<p>Instead, we recommend that you use either <a href="https://gunicorn.org/">Gunicorn</a> or <a href="https://www.uvicorn.org/">Uvicorn</a>, which are performant Python HTTP servers for WSGI applications. They allow you to run any Python application concurrently by running multiple Python processes within a single dyno.</p>
<p>Read <a href="https://devcenter.heroku.com/articles/python-gunicorn">Deploying Python Applications with Gunicorn</a> to learn how to set up Gunicorn for Python on Heroku.</p>
<h2 id="default-settings-and-behavior">Default Settings and Behavior</h2>
<div class="warning">
<p>If your application uses <a href="https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app">multiple buildpacks</a>, ensure that the <strong>Python buildpack</strong>, as the primary language buildpack of your application, executes <strong>after other language buildpacks</strong>. Otherwise, the app’s <code>WEB_CONCURRENCY</code> can default to the value set by a buildpack that runs after the Python one.</p>
</div>
<p>When booting an application, the Heroku Python buildpack automatically detects the CPU and memory specifications of the current <a href="https://devcenter.heroku.com/articles/dyno-types">dyno type</a>. It sets the <code>WEB_CONCURRENCY</code> environment variable to a suitable default value:</p>
<h4 id="common-runtime">Common Runtime</h4>
<table>
<thead>
<tr><th>Dyno Type</th><th>Default <code>WEB_CONCURRENCY</code></th></tr>
</thead>
<tbody>
<tr><td>Eco, Basic, Standard-1X</td><td>2</td></tr>
<tr><td>Standard-2X</td><td>4</td></tr>
<tr><td>Performance-M</td><td>5</td></tr>
<tr><td>Performance-L</td><td>17</td></tr>
</tbody>
</table>
<h4 id="private-spaces-and-shield-private-spaces">Private Spaces and Shield Private Spaces</h4>
<table>
<thead>
<tr><th>Dyno Type</th><th>Default <code>WEB_CONCURRENCY</code></th></tr>
</thead>
<tbody>
<tr><td>Private-S / Shield-S</td><td>4</td></tr>
<tr><td>Private-M / Shield-M</td><td>5</td></tr>
<tr><td>Private-L / Shield-L</td><td>17</td></tr>
</tbody>
</table>
<p>Both Gunicorn and Uvicorn will automatically use the value set by the <code>WEB_CONCURRENCY</code> environment variable to control the level of concurrency, or the number of child processes the parent process launches.</p>
<p>If your app uses a different web server, you must configure it to use the value set by <code>WEB_CONCURRENCY</code> for its number of workers. For example, if the server supports a <code>--workers</code> CLI argument, add <code>--workers $WEB_CONCURRENCY</code> to the server command listed under the <code>web</code> process in your <code>Procfile</code>.</p>
<h2 id="tuning-the-concurrency-level">Tuning the Concurrency Level</h2>
<p>Each app has unique memory, CPU, and I/O requirements, so there’s no such thing as a one-size-fits-all scaling solution. The Heroku Python buildpack provides reasonable default concurrency values for each dyno type, but some apps benefit from fine-tuning the concurrency level. See <a href="https://devcenter.heroku.com/articles/application-load-testing">Application Load Testing</a> for guidance on fine-tuning your application.</p>
<p>To manually set the number of child processes running your application, adjust the <code>WEB_CONCURRENCY</code> environment variable by setting a config var.</p>
<p>For instance, to statically set the number of child processes to 8, use:</p>
<pre class="language-term"><code class="language-term">$ heroku config:set WEB_CONCURRENCY=8
</code></pre>
<div class="warning">
<p>If you set <code>WEB_CONCURRENCY</code> to a fixed value, remember to adjust it when you scale to a different dyno type to optimize the use of the available RAM and CPUs on the new dyno type.</p>
</div>
<p>For Django-specific recommendations, see <a href="https://devcenter.heroku.com/articles/python-concurrency-and-database-connections">Concurrency and Database Connections in Django</a>.</p>tag:devcenter.heroku.com,2005:Article/80692024-03-11T19:12:42Z2024-03-11T19:12:42Zpgvector on Heroku Postgres<p>The <a href="https://github.com/pgvector/pgvector"><code>pgvector</code></a> extension for <a href="https://devcenter.heroku.com/articles/heroku-postgresql">Heroku Postgres</a> adds support for the vector data type. It adds functions for working with vectors, such as nearest neighbor search and cosine distance. Vectors are important for working with large language models and other machine learning applications, as the <a href="https://huggingface.co/blog/getting-started-with-embeddings#understanding-embeddings">embeddings</a> these models generate are often output in vector format.</p>
<h2 id="use-cases">Use Cases</h2>
<p>With <code>pgvector</code>, you can:</p>
<ul>
<li><strong>Perform retrieval augmented generation (RAG)</strong>: You can populate the database with vectorized embeddings that represent the semantic nature of the documents indexed, such as the latest product documentation for a specific domain. Given a query, RAG can retrieve the most relevant embeddings and the corresponding documents, which are then used to augment the context of the prompt for generative AI. The AI can then generate responses that are both accurate and contextually relevant.</li>
<li><strong>Recommend products</strong>: With a vector database containing various attributes, searching for alternatives based on the search criteria is simple. For example, you can make recommendations based on similar products like dresses or shirts, or match the style and color to offer pants or shoes. You can further extend this with collaborative filtering where the similar preferences of other shoppers enhance the recommendations.</li>
<li><strong>Search Salesforce data</strong>: Use <a href="https://devcenter.heroku.com/articles/heroku-connect">Heroku Connect</a> to synchronize Salesforce data into Heroku.Create a table with the embeddings since Heroku Connect can’t synchronize vector data types. For example, you can search for similar support cases with embeddings from Service Cloud cases.</li>
<li><strong>Search multimedia</strong>: Search across multimedia content, like images, audio, and video. You can <a href="https://www.sbert.net/examples/applications/image-search/README.html">embed the content</a> directly or work with transcriptions and other attributes to perform your search. For example, generating a music playlist by finding similar tracks based on embedded features like tempo, mood, genre, and lyrics.</li>
<li><strong>Categorize and segment data</strong>: From industries such as healthcare to manufacturing, data segmentation and categorization are key to successful data analysis. For example, by converting patient records, diagnostic data, or genomic sequences into vectors, you can identify similar cases, aiding in rare disease diagnosis and personalized treatment recommendations.</li>
<li><strong>Detect anomalies</strong>: Detect anomalies in your data by comparing vectors that don’t fit the regular pattern. This comparison is useful in analyzing and detecting problematic or suspicious patterns in areas such as network traffic data, industrial sensor data, transactions data, or online behavior.</li>
<li><strong>Perform similarity searches:</strong> Perform simple vector similarity searches (VSS) based on the input query vector. Generally, query embeddings are used to search against the embeddings loaded into the database, but any vector data can work.</li>
</ul>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>You have a <a href="https://devcenter.heroku.com/articles/heroku-postgres-plans">Standard-tier and higher database</a> running PostgreSQL 15 or a <a href="https://devcenter.heroku.com/articles/postgres-essential-tier">beta Essential-tier database</a>.</li>
<li>You don’t have <a href="https://devcenter.heroku.com/articles/heroku-data-connectors">Heroku Streaming Data Connectors</a> set up on that database. Vector data types don’t sync.</li>
</ul>
<h2 id="provisioning">Provisioning</h2>
<p>You can install <code>pgvector</code> by running <code>CREATE EXTENSION vector;</code> in a <a href="https://devcenter.heroku.com/articles/managing-heroku-postgres-using-cli#pg-psql"><code>psql</code></a> session on your database.</p>
<pre class="language-term"><code class="language-term">$ heroku pg:psql DATABASE_URL -a example-app
--> Connecting to postgresql-octagonal-12345
psql (13.2, server 11.12 (Ubuntu 11.12-1.pgdg16.04+1))
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
example-app::DATABASE=> CREATE EXTENSION vector;
CREATE EXTENSION
example-app::DATABASE=>
</code></pre>
<p>To check what version is installed, run the following query from <code>psql</code>:</p>
<pre class="language-term"><code class="language-term">=> SELECT extversion FROM pg_extension WHERE extname = 'vector';
extversion
------------
0.5.0
(1 row)
</code></pre>
<h2 id="work-with-pgvector">Work with pgvector</h2>
<p>You can create a table with a vector column:</p>
<pre class="language-term"><code class="language-term">CREATE TABLE animals(id serial PRIMARY KEY, name VARCHAR(100), embedding VECTOR(100));
</code></pre>
<p>In the example, we created an <code>animals</code> table with an <code>embedding</code> vector column.</p>
<p>After creating a table, you can insert vectors:</p>
<pre class="language-term"><code class="language-term">INSERT INTO animals(name, embedding) VALUES ('llama', '[-0.15647223591804504,
…
-0.7506130933761597, 0.1427040845155716]');
</code></pre>
<p>In the example, we inserted <code>llama</code> in the <code>embedding</code> vector column.</p>
<p>You can also add a vector column to an existing table:</p>
<pre class="language-term"><code class="language-term">ALTER TABLE fruit ADD COLUMN embedding VECTOR(100);
</code></pre>
<p>In the example, we added a vector column to an existing <code>fruit</code> table.</p>
<h2 id="perform-vector-queries">Perform Vector Queries</h2>
<p>You can perform different operations on your vector data with these common query operators.</p>
<h3 id="euclidean-distance"><->: Euclidean Distance</h3>
<p>The Euclidean distance, or L2 distance, operator measures the straight-line distance between two points in a vector. This operator is best for searching for an alternative item or most similar item to the query.</p>
<p>In the example, we use Euclidean distance search for animals similar to a shark in the <code>animals</code> table.</p>
<pre class="language-term"><code class="language-term">=> SELECT name FROM animals WHERE name != 'shark' ORDER BY embedding <-> (SELECT embedding FROM animals WHERE name = 'shark') LIMIT 5;
name
-----------
crocodile
dolphin
whale
turtle
alligator
(5 rows)
</code></pre>
<h3 id="negative-inner-product"><#>: Negative Inner Product</h3>
<p>The negative inner product operator measures the orthogonal projection, which is whether the vectors point in the same or opposite direction with magnitude. The greater the inner product means a greater similarity between two vectors. This operator is best for searching for items of similar topics and similar in magnitude. For example, image identification where an image of a shark yields the highest inner product against the embedding of a shark.</p>
<h3 id="cosine-distance"><=>: Cosine Distance</h3>
<p>The cosine distance operator measures the cosine of the angle between two vectors. The value ranges from -1 to 1, with values closer to 1 representing greater similarity between the vectors. This operator is best for similarity searches where it’s better to omit the magnitude. For example, anomaly detection where the frequency doesn’t matter, or text-based search for whole paragraph and document semantics.</p>
<h2 id="performance">Performance</h2>
<p>As you add more vector data to your database, there can be performance issues or slowness in performing queries. You can index vector data like other columns in Postgres, and <code>pgvector</code> provides <a href="https://github.com/pgvector/pgvector?tab=readme-ov-file#indexing">a few ways</a> to do so. Keep in mind:</p>
<ul>
<li>Adding an index causes <code>pgvector</code> to switch to using approximate nearest neighbor search instead of exact nearest neighbor search, possibly causing a difference in query results.</li>
<li>Indexing functions are based on distance calculations. Create functions based on the calculation you plan to rely on the most in your application.</li>
</ul>
<p>You can set the following settings to help optimize performance.</p>
<p><a href="https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-MAX-PARALLEL-WORKERS-PER-GATHER"><code>max_parallel_workers_per_gather</code></a> speeds up queries without creating an index.</p>
<pre class="language-term"><code class="language-term">SET max_parallel_workers_per_gather = 4;
</code></pre>
<p><a href="https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-MAX-PARALLEL-MAINTENANCE-WORKERS"><code>max_parallel_maintenance_workers</code></a> speeds up creating indexes on large tables by increasing the number of parallel workers.</p>
<pre class="language-term"><code class="language-term">SET max_parallel_maintenance_workers = 7;
</code></pre>
<p>To see the current settings, use the <code>SHOW</code> command:</p>
<pre class="language-term"><code class="language-term">=> SHOW max_parallel_workers_per_gather;
max_parallel_workers_per_gather
---------------------------------
1
(1 row)
</code></pre>
<p>See the <a href="https://github.com/pgvector/pgvector#performance"><code>pgvector</code> documentation</a> for guidance on creating indexes and optimizing performance on vector data types.</p>
<h3 id="indexes">Indexes</h3>
<p><code>pgvector</code> supports two index types: HNSW (Hierarchical Navigable Small Worlds) and IVFFlat (Inverted File with Flat Compression index). Depending on the type of index you choose, there are common trade-offs including speed, recall or the quality of the query result, build times, and resource consumption.</p>
<p>The default index type is having no index as <code>pgvector</code> is configured for exact nearest neighbor search. The default allows for perfect recall at the expense of speed. Adding an HNSW or IVFFlat index lets you perform approximate nearest neighbor (ANN) searches.</p>
<h4 id="hnsw">HNSW</h4>
<p>HNSW is the preferred index type for ANN searches as it performs better than IVFFlat in most use cases. However, HNSW indexes take longer to build and take more memory. The algorithm builds multi-layer graphs that allow for fast search results. The index is built as you insert data into the table, so you can create these indexes without any data.</p>
<h4 id="ivfflat">IVFFlat</h4>
<p>You can use IVFFlat indexes for improving performance on ANN searches, including searches against high-dimensional embeddings. Since the IVFFlat relies on an existing vector, it’s best to build the index after the table has data in it for better recall. If the data distribution changes significantly, rebuild the index. IVFFlat indexes have faster build times and take less memory than HNSW, but it has worse query performance.</p>
<h2 id="examples">Examples</h2>
<ul>
<li><a href="https://blog.heroku.com/pgvector-for-similarity-search-on-heroku-postgres">How to Use pgvector for Similarity Search on Heroku Postgres</a></li>
</ul>tag:devcenter.heroku.com,2005:Article/78402024-03-04T19:10:18Z2024-03-11T16:10:42ZHeroku Postgres Essential Tier (Public Beta)<p>The <a href="https://devcenter.heroku.com/changelog-items/2807">beta release</a> is available for customers interested in the newest Heroku Postgres Essential-tier plans. On improved infrastructure, the new plans no longer have a row limit and also support the <a href="https://devcenter.heroku.com/articles/heroku-postgres-extensions-postgis-full-text-search#pgvector"><code>pgvector</code></a> extension. This beta gives customers an early opportunity to experiment and provide feedback that helps guide us toward delivering world-class, user-centric database services.</p>
<div class="note">
<p>The Heroku Postgres Essential tier is currently in public beta. The products offered as part of the beta aren’t intended for production use and are considered as a Beta Service and are subject to the Beta Services terms at <a href="https://www.salesforce.com/company/legal/agreements.jsp">https://www.salesforce.com/company/legal/agreements.jsp</a>.</p>
</div>
<p class="devcenter-parser-special-block-separator" style="display:none"> </p>
<div class="note">
<p>This public beta doesn’t cover the <a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#essential-tier">existing <code>mini</code> and <code>basic</code> plans</a>. See <a href="#plan-details">Plan Details</a> for the beta plans.</p>
</div>
<h2 id="beta-details">Beta Details</h2>
<ul>
<li>It’s free to participate and use the new Essential-tier products. To submit feedback on the new plans, <a href="https://help.heroku.com/">open a support ticket</a> and use the subject line <code>Heroku Postgres Essential Beta Feedback: <feedback></code>. If you have any questions or concerns, use the subject line <code>Heroku Postgres Essential Beta Support: <issue></code> in your support ticket.</li>
<li>We reserve the right to shut down the test databases and the public beta at any point for any or no reason.</li>
</ul>
<h2 id="getting-started">Getting Started</h2>
<h3 id="provision-the-database">Provision the Database</h3>
<p>These plans are available through the <a href="http://data.heroku.com">dashboard</a> and the <a href="https://devcenter.heroku.com/articles/heroku-cli">CLI</a>. Use this command to provision a database through the CLI.</p>
<pre class="language-term"><code class="language-term">$ heroku addons:create heroku-postgresql:essential-1 --app example-app
</code></pre>
<p>To see the details of your database, use the <a href="https://devcenter.heroku.com/articles/managing-heroku-postgres-using-cli#pg-info"><code>pg:info</code></a> command:</p>
<pre class="language-term"><code class="language-term">$ heroku pg:info -a example-app
=== HEROKU_POSTGRESQL_RED
Plan Essential 1
Status available
Data Size 2.8 GB
Tables 13
PG Version 15
Created 2024-03-01 09:58 PDT
…
</code></pre>
<h3 id="plan-details">Plan Details</h3>
<p>The beta Essential-tier plans are available on <a href="https://devcenter.heroku.com/articles/heroku-postgres-version-support">Postgres versions</a> 15 and 14. The beta introduces three new plans in the <a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#essential-tier">Essential tier</a>:</p>
<table><thead>
<tr>
<th>Product</th>
<th>Provisioning Name</th>
<th>Disk</th>
<th>Connection Limit</th>
<th>Row Limit</th>
<th>Table Count Limit</th>
<th>Status</th>
</tr>
</thead><tbody>
<tr>
<td>Essential-0</td>
<td><code>heroku-postgresql:essential-0</code></td>
<td>1 GB</td>
<td>20</td>
<td>No limit</td>
<td>4,000</td>
<td>Beta</td>
</tr>
<tr>
<td>Essential-1</td>
<td><code>heroku-postgresql:essential-1</code></td>
<td>10 GB</td>
<td>20</td>
<td>No limit</td>
<td>4,000</td>
<td>Beta</td>
</tr>
<tr>
<td>Essential-2</td>
<td><code>heroku-postgresql:essential-2</code></td>
<td>32 GB</td>
<td>40</td>
<td>No limit</td>
<td>4,000</td>
<td>Beta</td>
</tr>
</tbody></table>
<h2 id="work-with-your-database">Work With Your Database</h2>
<p>The beta Essential-tier plans support the <a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#shared-features">shared features</a> in all Heroku Postgres plans except for versions supported.</p>
<h3 id="install-extensions">Install Extensions</h3>
<p>The beta Essential-tier plans support all the extensions listed in <a href="https://devcenter.heroku.com/articles/heroku-postgres-extensions-postgis-full-text-search">Extensions, PostGIS, and Full Text Search Dictionaries on Heroku Postgres</a>.</p>
<h3 id="upgrade-your-plan-with-pg-copy">Upgrade Your Plan with pg:copy</h3>
<p>You can migrate data from your existing <code>mini</code> and <code>basic</code> databases to the beta Essential-tier plans with <a href="https://devcenter.heroku.com/articles/updating-heroku-postgres-databases#updating-with-pg-copy"><code>pg:copy</code></a>. Make sure the table count in your existing database is within the <a href="#plan-details">plan limits</a> before upgrading. To find your table usage, run the <a href="https://devcenter.heroku.com/articles/managing-heroku-postgres-using-cli#pg-info"><code>pg:info</code></a> command.</p>
<h3 id="back-up-your-data-with-pgbackups">Back Up Your Data with PGBackups</h3>
<p>You can create manual backups or schedule backups with <a href="https://devcenter.heroku.com/articles/heroku-postgres-backups">PGBackups</a>. Beta Essential databases have the following limits on manual and scheduled backups.</p>
<table><thead>
<tr>
<th>Plan</th>
<th>Manual Backups Retained</th>
<th>Scheduled Daily Backups Retained</th>
<th>Scheduled Weekly Backups Retained</th>
<th>Scheduled Monthly Backup Retained</th>
</tr>
</thead><tbody>
<tr>
<td>Essential-*</td>
<td>5</td>
<td>7 days</td>
<td>1 week</td>
<td>0 months</td>
</tr>
</tbody></table>
<h3 id="run-diagnostics-with-pg-diagnose">Run Diagnostics with pg:diagnose</h3>
<p>You can perform useful health and diagnostic checks that help analyze and optimize database performance with <a href="https://devcenter.heroku.com/articles/heroku-postgres-performance-analytics#pg-diagnose">pg:diagnose</a>.</p>
<h3 id="create-and-share-dataclips">Create and Share Dataclips</h3>
<p>You can create SQL queries on your databases and share the results with <a href="https://devcenter.heroku.com/articles/dataclips">Dataclips</a>.</p>
<h2 id="plan-limit-enforcement">Plan Limit Enforcement</h2>
<p>Plan limits are enforced with the following mechanism:</p>
<ol>
<li>When a beta Essential database reaches 90% of a usage limit, the owner receives a warning email.</li>
<li>When the database exceeds a limit, the owner receives an additional notification. At this point, the database receives a 7-day grace period to comply with the limit or <a href="https://devcenter.heroku.com/articles/updating-heroku-postgres-databases#updating-with-pg-copy">migrate to another plan</a>.</li>
<li>If the database is still exceeding any plan limits after 7 days, we revoke <code>INSERT</code> and <code>UPDATE</code> privileges and we limit the number of connections to 1 on the database. You can still read, update, or delete data from the database so that you can bring your database into compliance and retain access to your data.</li>
<li>If the database is still exceeding in violation of our policy, we remove all connections for an additional 7 days. The owner must create a support ticket to regain access to the database.</li>
<li>When the usage is again in compliance with the plan limit, we automatically restore privileges and connections to the database. Restoring privileges can take some time. If the usage continues to exceed the plan limit, we flag the database for deletion due to non-compliance to our policy.</li>
</ol>tag:devcenter.heroku.com,2005:Article/77662024-02-01T08:38:29Z2024-02-01T08:38:29ZSchema To Go<p><a href="https://elements.heroku.com/addons/schematogo">Schema To Go</a> is a robust PostgreSQL database service tailored for Heroku applications. It offers reliable, secure, and scalable database solutions to enhance the data handling capabilities of your applications.</p>
<h2 id="features">Features</h2>
<ul>
<li><strong>High Performance</strong>: Powered by PostgreSQL, Schema To Go ensures efficient data management.</li>
<li><strong>Easy Integration</strong>: Easily integrates with Heroku apps.</li>
<li><strong>Automated Backups</strong>: Regular backups for data safety.</li>
<li><strong>Data Security</strong>: High priority on data encryption and security.</li>
<li><strong>Monitoring and Analytics</strong>: Detailed insights into database performance and usage.</li>
</ul>
<h2 id="provisioning-the-add-on">Provisioning the Add-On</h2>
<p>Add Schema To Go to your application via the CLI:</p>
<div class="callout">
<p>Reference the <a href="https://elements.heroku.com/addons/schematogo">Schema To Go Elements Page</a> for a list of available plans and regions.</p>
</div>
<pre class="language-bash"><code class="language-bash">heroku addons:create schematogo --app example-app
</code></pre>
<h2 id="local-setup">Local Setup</h2>
<h3 id="environment-setup">Environment Setup</h3>
<p>After provisioning the add-on, replicate its config vars locally for development environments that need the service.</p>
<p>Use the <code>local</code> <a href="https://devcenter.heroku.com/articles/heroku-cli">Heroku CLI</a> command to configure, run, and manage process types specified in your app’s <a href="https://devcenter.heroku.com/articles/procfile">Procfile</a>. Heroku Local reads configuration variables from a <code>.env</code> file. Use <code>heroku config</code> to view an app’s configuration variables in a terminal. Use the following command to add a configuration variable to a local <code>.env</code> file:</p>
<pre class="language-term"><code class="language-term">$ heroku config:get schematogo -s >> .env
</code></pre>
<div class="warning">
<p>Don’t commit credentials and other sensitive configuration variables to source control. In Git exclude the <code>.env</code> file with: <code>echo .env >> .gitignore</code>.</p>
</div>
<p>For more information, see the <a href="https://devcenter.heroku.com/articles/heroku-local">Heroku Local</a> article.</p>
<h2 id="configuring-your-application">Configuring Your Application</h2>
<p>After provisioning, Schema To Go sets the <code>SCHEMATOGO_URL</code> environment variable. Configure your application to use this variable:</p>
<h3 id="using-postgresql-from-ruby">Using PostgreSQL from Ruby</h3>
<p>To configure your application with Ruby:</p>
<pre class="language-ruby"><code class="language-ruby">require 'pg'
if ENV['SCHEMATOGO_URL']
conn = PG.connect(ENV['SCHEMATOGO_URL'])
# Your code here
end
</code></pre>
<h3 id="using-postgresql-from-java">Using PostgreSQL from Java</h3>
<p>To configure your application with Java:</p>
<pre class="language-java"><code class="language-java">import java.sql.Connection;
import java.sql.DriverManager;
public class PostgresExample {
public static void main(String[] args) {
String dbUrl = System.getenv("SCHEMATOGO_URL");
try {
Connection connection = DriverManager.getConnection(dbUrl);
// Your code here
} catch (Exception e) {
e.printStackTrace();
}
}
}
</code></pre>
<h3 id="using-postgresql-from-python">Using PostgreSQL from Python</h3>
<p>To configure your application with Python:</p>
<pre class="language-python"><code class="language-python">import os
import psycopg2
database_url = os.getenv('SCHEMATOGO_URL')
conn = psycopg2.connect(database_url)
# Your code here
</code></pre>
<h3 id="using-postgresql-from-node-js">Using PostgreSQL from Node.js</h3>
<p>To configure your application with Node.js:</p>
<pre class="language-javascript"><code class="language-javascript">const { Pool } = require('pg');
const pool = new Pool({
connectionString: process.env.SCHEMATOGO_URL
});
// Your code here
</code></pre>
<h3 id="using-postgresql-from-php">Using PostgreSQL from PHP</h3>
<p>To configure your application with PHP:</p>
<pre class="language-php"><code class="language-php"><?php
$dbUrl = getenv('SCHEMATOGO_URL');
if ($dbUrl) {
$pdo = new PDO($dbUrl);
// Your code here
}
?>
</code></pre>
<h3 id="using-postgresql-from-go">Using PostgreSQL from Go</h3>
<p>To configure your application with Go:</p>
<pre class="language-go"><code class="language-go">package main
import (
"database/sql"
"os"
_ "github.com/lib/pq"
)
func main() {
databaseURL := os.Getenv("SCHEMATOGO_URL")
db, err := sql.Open("postgres", databaseURL)
if err != nil {
panic(err)
}
defer db.Close()
// Your code here
}
</code></pre>
<div class="note">
<p>These snippets provide basic guidance for integrating Schema To Go with various applications. Include additional details specific to your add-on’s capabilities and configurations.</p>
</div>
<h2 id="migrating-between-plans">Migrating Between Plans</h2>
<div class="note">
<p>Application owners must carefully manage the migration timing to ensure proper application function during the migration process.</p>
</div>
<p>To migrate to a new plan, use the <code>heroku addons:upgrade</code> command:</p>
<pre class="language-bash"><code class="language-bash">heroku addons:upgrade schematogo:new-plan
</code></pre>
<h2 id="removing-the-add-on">Removing the Add-On</h2>
<p>Before removing Schema To Go from your application, ensure to download a recent copy of your database to prevent any data loss. You can download the latest backup directly from the <strong><code>Backups</code></strong> section of the Schema To Go dashboard.</p>
<p>To download your data:</p>
<ol>
<li>Navigate to the Schema To Go dashboard.</li>
<li>Scroll to the <strong><code>Backups</code></strong> section.</li>
<li>Click the most recent backup in the list.</li>
<li>Follow the prompts to download the backup file to your local machine.</li>
</ol>
<p>If you encounter any issues or need assistance, contact our support team at <a href="mailto:support@schematogo.com">support@schematogo.com</a>.</p>
<p>After securing your data, you can remove Schema To Go from your application with the following command:</p>
<div class="warning">
<p>This action destroys all associated data and you can’t undo it!</p>
</div>
<pre class="language-bash"><code class="language-bash">heroku addons:destroy schematogo
</code></pre>
<h2 id="support">Support</h2>
<p>For any questions or issues, contact our support team at <a href="mailto:support@schematogo.com">support@schematogo.com</a>.</p>
<h2 id="additional-resources">Additional Resources</h2>
<p><a href="https://www.postgresql.org/docs/">PostgreSQL Official Documentation</a></p>tag:devcenter.heroku.com,2005:Article/77652024-02-01T08:37:34Z2024-02-01T08:37:34ZCache To Go<p><a href="https://elements.heroku.com/addons/cachetogo">Cache To Go</a> is a powerful Redis service designed for Heroku applications. It offers fast, reliable, and easy-to-integrate caching and storage solutions to improve the performance and scalability of your applications.</p>
<h2 id="features">Features</h2>
<ul>
<li><strong>High Performance</strong>: Leveraging Redis, Cache To Go delivers high-speed data access.</li>
<li><strong>Easy Integration</strong>: Seamlessly integrates with Heroku apps.</li>
<li><strong>Scalability</strong>: Scales with your application’s needs.</li>
<li><strong>Data Security</strong>: Ensures data is secure and private.</li>
<li><strong>Monitoring and Metrics</strong>: Comprehensive insights into usage and performance.</li>
</ul>
<h2 id="provisioning-the-add-on">Provisioning the Add-On</h2>
<p>Add Cache To Go to your application via the CLI:</p>
<div class="callout">
<p>Reference the <a href="https://elements.heroku.com/addons/cachetogo">Cache To Go Elements Page</a> for a list of available plans and regions.</p>
</div>
<pre class="language-bash"><code class="language-bash">heroku addons:create cachetogo --app example-app
</code></pre>
<h2 id="local-setup">Local Setup</h2>
<h3 id="environment-setup">Environment Setup</h3>
<p>After provisioning the add-on, replicate its config vars locally for development environments that need the service.</p>
<p>Use the <code>local</code> <a href="https://devcenter.heroku.com/articles/heroku-cli">Heroku CLI</a> command to configure, run, and manage process types specified in your app’s <a href="https://devcenter.heroku.com/articles/procfile">Procfile</a>. Heroku Local reads configuration variables from a <code>.env</code> file. Use <code>heroku config</code> to view an app’s configuration variables in a terminal. Use the following command to add a configuration variable to a local <code>.env</code> file:</p>
<pre class="language-term"><code class="language-term">$ heroku config:get cachetogo -s >> .env
</code></pre>
<div class="warning">
<p>Don’t commit credentials and other sensitive configuration variables to source control. In Git exclude the <code>.env</code> file with: <code>echo .env >> .gitignore</code>.</p>
</div>
<p>For more information, see the <a href="https://devcenter.heroku.com/articles/heroku-local">Heroku Local</a> article.</p>
<h2 id="configuring-your-application">Configuring Your Application</h2>
<p>After provisioning, Cache To Go sets the <code>CACHETOGO_URL</code> environment variable. Use this variable to configure your application:</p>
<h3 id="using-redis-from-ruby">Using Redis from Ruby</h3>
<pre class="language-ruby"><code class="language-ruby">require 'redis'
if ENV['CACHETOGO_URL']
$redis = Redis.new(url: ENV['CACHETOGO_URL'])
end
</code></pre>
<h3 id="using-redis-from-java">Using Redis from Java</h3>
<p>For Java applications, use the following method to integrate Cache To Go:</p>
<pre class="language-java"><code class="language-java">import redis.clients.jedis.Jedis;
public class RedisExample {
public static void main(String[] args) {
String redisUrl = System.getenv("CACHETOGO_URL");
Jedis jedis = new Jedis(redisUrl);
// Your code here
}
}
</code></pre>
<h3 id="using-redis-from-python">Using Redis from Python</h3>
<p>In Python, you can integrate Cache To Go like this:</p>
<pre class="language-python"><code class="language-python">import os
import redis
redis_url = os.getenv('CACHETOGO_URL')
redis_client = redis.Redis.from_url(redis_url)
# Your code here
</code></pre>
<h3 id="using-redis-from-node-js">Using Redis from Node.js</h3>
<p>For integrating Cache To Go in a Node.js application, use the following example:</p>
<pre class="language-javascript"><code class="language-javascript">const redis = require('redis');
const client = redis.createClient(process.env.CACHETOGO_URL);
client.on('connect', function() {
console.log('Connected to Redis');
});
// Your code here
</code></pre>
<h3 id="using-redis-from-php">Using Redis from PHP</h3>
<p>To integrate Cache To Go with a PHP application:</p>
<pre class="language-php"><code class="language-php"><?php
if (getenv('CACHETOGO_URL')) {
$redis = new Redis();
$redis->connect(getenv('CACHETOGO_URL'));
// Your code here
}
?>
</code></pre>
<h3 id="using-redis-from-go">Using Redis from Go:</h3>
<pre class="language-go"><code class="language-go">package main
import (
"github.com/go-redis/redis"
"os"
)
func main() {
redisURL := os.Getenv("CACHETOGO_URL")
opt, err := redis.ParseURL(redisURL)
if err != nil {
panic(err)
}
client := redis.NewClient(opt)
// Your code here
}
</code></pre>
<div class="note">
<p>These snippets provide a basic guide for integrating Cache To Go into various applications. Be sure to include additional details specific to your add-on’s capabilities and configurations.</p>
</div>
<h2 id="migrating-between-plans">Migrating Between Plans</h2>
<div class="note">
<p>Application owners must carefully manage the migration timing to ensure proper application function during the migration process.</p>
</div>
<p>Use the <code>heroku addons:upgrade</code> command to migrate to a new plan.</p>
<pre class="language-bash"><code class="language-bash">heroku addons:upgrade cachetogo:new-plan
</code></pre>
<h2 id="removing-the-add-on">Removing the Add-On</h2>
<h3 id="exporting-your-data-before-removal">Exporting Your Data Before Removal</h3>
<p>Before removing the add-on, it’s important to ensure that your data is safe and retrievable. Cache To Go offers a manual process for data export:</p>
<ol>
<li><p>Email the support team at support@cachetogo.com with the subject line “Data Export Request”.</p></li>
<li><p>Include your account and add-on details in the email.</p></li>
<li><p>Cache To Go’s support team processes your request and provides you with a link to download your data.</p></li>
</ol>
<h3 id="remove-cache-to-go-from-your-application">Remove Cache To Go from your application:</h3>
<div class="warning">
<p>This action destroys all associated data and you can’t undo it!</p>
</div>
<pre class="language-bash"><code class="language-bash">heroku addons:destroy cachetogo
</code></pre>
<h2 id="support">Support</h2>
<p>Contact our support team for any questions or issues at support@cachetogo.com.</p>
<h2 id="additional-resources">Additional Resources</h2>
<ul>
<li><a href="https://redis.io/documentation">Redis Official Documentation</a>
“`</li>
</ul>tag:devcenter.heroku.com,2005:Article/77942023-09-27T18:31:39Z2024-02-12T23:00:25ZRouter 2.0 (Public Beta)<p>The beta release for Heroku’s new Common Runtime router, Router 2.0, gives customers an early opportunity to experiment and provide feedback to shape the future of our networking product. You can opt into the beta by <a href="#enable-router-2-0">following the instructions here</a>.</p>
<p>This new router is specific to Eco, Basic, Standard, and Performance dynos in the <a href="https://devcenter.heroku.com/articles/dyno-runtime#common-runtime">Heroku’s Common Runtime</a>. This feature isn’t available for <a href="https://devcenter.heroku.com/articles/heroku-enterprise#available-dyno-types">Private or Shield dynos</a> in Private Spaces.</p>
<p>As an early adopter, you can help us validate that things are working as they should, particularly for your apps and use cases. You also automatically get access to future web features, such as HTTP/2, as we make updates to Router 2.0. The current Common Runtime production router won’t receive new features going forward.</p>
<p>If you participate in the beta, you can submit feedback by commenting on the <a href="https://github.com/heroku/roadmap/issues/219">Heroku Public Roadmap item</a> or by <a href="https://help.heroku.com/tickets/new?id=4">creating a support ticket</a>.</p>
<div class="note">
<p>This feature is in public beta and is subject to change. Use of this feature is subject to the <a href="https://www.salesforce.com/company/legal/agreements.jsp">Beta Services terms</a>.</p>
</div>
<p class="devcenter-parser-special-block-separator" style="display:none"> </p>
<div class="note">
<p>Router 2.0 is a Heroku Labs feature. Heroku SLAs as covered in the <a href="https://www.heroku.com/policy/support">Heroku Support Policy</a> don’t apply. Support tickets related to this beta are considered product feedback.</p>
</div>
<h2 id="current-and-future-state">Current and Future State</h2>
<p>As we develop the new router, we plan to continue adding the features in the following table to reach parity with our current Common Runtime router.</p>
<div class="warning">
<p>Features added through Heroku Labs are experimental and subject to change.</p>
</div>
<p>The new router supports the following features:</p>
<table><thead>
<tr>
<th>Feature</th>
<th>Current Common Runtime Router</th>
<th>Router 2.0</th>
<th>Notes</th>
</tr>
</thead><tbody>
<tr>
<td><a href="https://devcenter.heroku.com/articles/http-routing#routing">Routing</a></td>
<td>x</td>
<td>x</td>
<td>Basic routing, including TLS termination is supported.</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/http-routing#heroku-router-log-format">Router logs</a></td>
<td>x</td>
<td>x</td>
<td>Per-request router logs appear in your app’s log stream.</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/error-codes">Error codes</a></td>
<td>x</td>
<td>x</td>
<td>Most H codes are supported and reported in router logs. Currently, the only exceptions are H23 and H26.</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/eco-dyno-hours#dyno-sleeping">Dyno sleeping</a></td>
<td>x</td>
<td>x</td>
<td>Dyno sleeping (idling) is supported for Eco dynos.</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/http-routing#request-concurrency-limiting">Request concurrency limiting</a></td>
<td>x</td>
<td>x</td>
<td>Each router maintains an internal per-app request counter and limits the number of concurrent requests per app.</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/http-routing#heroku-headers">Heroku headers</a></td>
<td>x</td>
<td>x</td>
<td>Heroku Headers are a set of headers that Heroku adds to HTTP responses.</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/http-routing#websockets">WebSockets</a></td>
<td>x</td>
<td></td>
<td>Coming soon for Router 2.0</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/http-routing#expect-100-continue">Expect 100-continue</a></td>
<td>x</td>
<td></td>
<td>Coming soon for Router 2.0</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/http-routing#dyno-connection-behavior-on-the-common-runtime">Dyno quarantining</a></td>
<td>x</td>
<td></td>
<td>Router 2.0 retries on failed connection attempts, but it does not currently quarantine dynos.</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/preboot">Preboot</a></td>
<td>x</td>
<td></td>
<td>Coming soon for Router 2.0</td>
</tr>
<tr>
<td><a href="https://devcenter.heroku.com/articles/session-affinity">Session affinity</a></td>
<td>x</td>
<td></td>
<td>Coming soon for Router 2.0</td>
</tr>
<tr>
<td>HTTP/2</td>
<td></td>
<td></td>
<td>Coming soon for Router 2.0 only</td>
</tr>
<tr>
<td>IPV6</td>
<td></td>
<td></td>
<td>Coming soon for Router 2.0 only</td>
</tr>
</tbody></table>
<p>For a full list of HTTP routing features of our current Common Runtime router, see <a href="https://devcenter.heroku.com/articles/http-routing">HTTP Routing</a>.</p>
<div class="note">
<p>We’ll update this table and announce new features in our <a href="https://devcenter.heroku.com/changelog">changelog</a> as we add them to the new router.</p>
</div>
<h2 id="enable-router-2-0">Enable Router 2.0</h2>
<p>To opt into using the new router, enable the labs feature:</p>
<pre><code>$ heroku labs:enable http-routing-2-dot-0 -a <app name>
</code></pre>
<p>After enabling this feature, your app will start receiving traffic through Router 2.0, our new Common Runtime router.</p>
<div class="note">
<p>Clients must re-establish their connection to your app after enabling or disabling the <code>http-routing-2-dot-0</code> flag.</p>
</div>
<h2 id="disable-router-2-0">Disable Router 2.0</h2>
<p>To stop using the new router, disable the <code>http-routing-2-dot-0</code> flag. You don’t need to do anything else to return your app to its previous routing behavior.</p>
<p>To stop using Router 2.0:</p>
<pre><code>$ heroku labs:disable http-routing-2-dot-0 -a <app name>
</code></pre>tag:devcenter.heroku.com,2005:Article/77292023-08-07T16:03:05Z2023-08-07T16:03:05ZAsynchronous Deprovisioning of Add-ons (Public Beta)<p>The Asynchronous Deprovisioning feature allows add-on providers to act on an app where the add-on resource is attached before the provider’s access is removed by deprovisioning. Depending on the add-on provider, they can perform actions like shutting down one-off dynos or removing SSL certificates created by the add-on. You can also send follow-up communication to the customer, and so on.</p>
<div class="note">
<p>This feature is in public beta. To request access, <a href="https://help.heroku.com/new/ecosystem-support">open a support ticket</a>.</p>
</div>
<h2 id="example-workflow">Example Workflow</h2>
<p><img src="https://assets.devcenter.heroku.com/article-images/1690225862-async_deprovision_seq_diagram.png" alt="Async Deprovisioning Sequence Diagram"></p>
<p>In the example, the add-on provider performs an ordered shutdown of their scheduler service by stopping all one-off dynos on the add-on. Then it sends relevant log messages to the application log before losing access to the customer application.</p>
<ol>
<li>The customer requests to remove the add-on from the application by running the <a href="https://devcenter.heroku.com/articles/managing-add-ons#destroying-an-add-on"><code>addons:destroy</code></a> command through Heroku CLI.</li>
<li>We stop billing for the add-on resource and send an <code>Async Allowed</code> add-on deprovision request to the partner.</li>
<li>The partner responds to the deprovision request with a <code>202 Accepted</code> response code.</li>
<li>The partner sends a request to the <a href="https://devcenter.heroku.com/articles/platform-api-reference#dyno-stop">Dyno Stop endpoint</a> for each of their controlled one-off dynos that are still running.</li>
<li>The partner sends a log message for each dyno stopped containing relevant information for the customer. The information includes the timestamp of when the dyno was killed, the command being executed, and the reason for killing it (add-on deprovisioning) using the <a href="https://devcenter.heroku.com/articles/add-on-partner-log-integration">log input URL</a> linked with the add-on resource.</li>
<li>The partner makes an explicit call that tells Heroku that they’re done and don’t require further access to the Platform API on behalf of this resource.</li>
<li>We detach and remove the resource from the application, including the partner authorization. This step triggers an app restart.</li>
</ol>
<p>See the <a href="#implementation">Implementation section</a> for the specifics of each part of this process.</p>
<h2 id="things-to-know">Things to Know</h2>
<h3 id="billing">Billing</h3>
<p>Billing stops when the customer requests to deprovision the add-on. The time and cost of deprovisioning your service isn’t accounted for in how much a customer pays. Make sure to deprovision promptly so you don’t incur unnecessary costs.</p>
<h3 id="incomplete-add-on-deprovisionings">Incomplete Add-on Deprovisionings</h3>
<p>Add-ons that take longer than 12 hours to deprovision, or add-ons that your service fails to mark as <code>deprovisioned</code> via the API in that time period, are still considered deprovisioned. They are removed from customer apps and we don’t bill customers for provider delays in deprovisioning.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>You must use the <a href="https://devcenter.heroku.com/articles/platform-api-for-partners">Platform API for Partners</a>.</li>
<li>To request access to this beta feature, <a href="https://help.heroku.com/new/ecosystem-support">open a support ticket</a>.</li>
</ul>
<h2 id="implementation">Implementation</h2>
<h3 id="determine-if-async-deprovisioning-is-allowed-for-a-resource">Determine if Async Deprovisioning is Allowed for a Resource</h3>
<p>When we grant your add-on service access to Async Deprovisioning, all of our deprovision requests include an <code>X-Async-Deprovision-Allowed</code> header. It has a value of <code>true</code> or <code>false</code>.</p>
<p>Sometimes you can’t deprovision asynchronously. When an add-on is deprovisioned because the app is destroyed, the header is set to <code>false</code> and you receive the request after Heroku destroys both the add-on resource and the app. Any attempt to use the Platform API in this scenario results in <code>401 Unauthorized</code> because of revoked and invalid access tokens.</p>
<p>An <code>X-Async-Deprovision-Allowed</code> header set to <code>true</code> indicates the customer requested to remove the add-on and you can deprovision asynchronously.</p>
<h3 id="respond-to-the-provision-request-with-a-202-accepted">Respond to the Provision Request with a 202 Accepted</h3>
<p>If your add-on service has access to the beta Asynchronous Deprovisioning feature and we send a deprovision request with the <code>X-Async-Deprovision-Allowed</code> header set to <code>true</code>, your add-on <em>must</em>:</p>
<ol>
<li>Enqueue a job to deprovision the resource asynchronously.</li>
<li>Respond with a <code>202 Accepted</code> response code.</li>
</ol>
<p>This process tells Heroku to keep your add-on in a deprovisioning state, without removing your access tokens. You must explicitly mark the add-on as <code>deprovisioned</code> when you no longer require access to the Platform API.</p>
<div class="note">
<p>For some resources, the Asynchronous Deprovisioning workflow isn’t appropriate. In that case, your service can respond with any other <code>2xx Successful</code> response code besides <code>202 Accepted</code>, and we immediately deprovision the add-on. Either a <code>204 No Content</code> (preferred) or <code>200 Ok</code> response works.</p>
</div>
<h3 id="perform-the-required-actions-on-the-app">Perform the Required Actions on the App</h3>
<p>While the add-on is in a deprovisioning state, your access and refresh tokens are still valid to perform actions on the Platform API.</p>
<p>You <em>must</em> mark the add-on as <code>deprovisioned</code> as soon as you complete any pending actions over the customer’s app. We encourage you to access the Platform API to perform an ordered shutdown as soon as possible.</p>
<p>If your add-on service deprovisioning workflow requires time-consuming operations like database backups or infrastructure teardown, use background jobs to perform these actions after you mark the resource as <code>deprovisioned</code>. We don’t require providers to fully deprovision the resource on their side to mark the add-on <code>deprovisioned</code>.</p>
<h3 id="finish-add-on-deprovisioning">Finish Add-on Deprovisioning</h3>
<p>The final step is to tell Heroku that you deprovisioned the add-on and you don’t need further access to the Platform API. If this step isn’t taken within 12 hours of the deprovisioning request, we consider it completed and remove the add-on along with provider access. To indicate that deprovisioning has completed, use the <a href="https://devcenter.heroku.com/articles/platform-api-reference#add-on-action-deprovision">Add-on Action Deprovision endpoint</a>.</p>
<pre><code>POST /addons/:uuid/actions/deprovision
</code></pre>
<p>At this point, the add-on and provider access and add-on config vars are removed. We create a new release and restart all application dynos.</p>
<h2 id="summary">Summary</h2>
<p>Asynchronous Deprovisioning allows add-on partners to implement better and richer user experiences during deprovisioning. Providers must make a few changes to how they integrate with our APIs and have the feature enabled. Contact the Heroku <a href="https://help.heroku.com/new/ecosystem-support">Ecosystem Engineering team</a> with any implementation-related questions.</p>tag:devcenter.heroku.com,2005:Article/77322023-07-31T20:00:13Z2023-11-08T16:10:12ZSalesforce Functions Retirement<p>On January 31, 2025, Salesforce is retiring Salesforce Functions, also known as Salesforce Elastic Services. To preserve the capabilities that Salesforce Functions provided to your org, you must deploy an alternative solution before your existing Order Term ends. This article describes the retirement timeline and how you can replace your Salesforce Functions.</p>
<h2 id="retirement-timeline">Retirement Timeline</h2>
<div class="callout">
<p>These dates are subject to change. We update these dates as soon as we’re aware of changes.</p>
</div>
<p>The Salesforce Functions product retirement process includes three important dates:</p>
<table><thead>
<tr>
<th>Status</th>
<th>Description</th>
<th>Planned Date</th>
</tr>
</thead><tbody>
<tr>
<td>End of Sale (EOS)</td>
<td>The last day customers can purchase new Elastic Services subscriptions.</td>
<td>October 31, 2023</td>
</tr>
<tr>
<td>End of Renewal (EOR)</td>
<td>The last day customers can renew their existing Elastic Services subscription.</td>
<td>January 31, 2024</td>
</tr>
<tr>
<td>End of Life (EOL)</td>
<td>The last day Elastic Services is available in Salesforce orgs.</td>
<td>January 31, 2025</td>
</tr>
</tbody></table>
<h2 id="salesforce-functions-migration">Salesforce Functions Migration</h2>
<p>To avoid disruption to your org after the Salesforce Functions end-of-life date, you must migrate the functionality to a different product. One alternative is to redeploy your functions as Heroku apps using this example <a href="https://github.com/heroku/function-migration">migration repository</a> as your guide.</p>
<p>The <a href="https://github.com/heroku/function-migration">migration repository</a> includes sample code and Apex classes to invoke your functions and replace the Elastic Services API in your Salesforce org.</p>
<h2 id="salesforce-integration-roadmap">Salesforce Integration Roadmap</h2>
<p>The Heroku Roadmap includes new integration capabilities via Heroku <a href="https://github.com/heroku/roadmap/issues/185">Add-ons</a>.</p>
<p>The Salesforce add-on aims to provide customers with an effortless and reliable connection to Salesforce CRM, based on industry standards. This quick add-on solution addresses the recurring need for a simple and durable integration between Salesforce and Heroku. It focuses on implementing industry-leading security practices, ensuring a secure and efficient connection between the two platforms.</p>tag:devcenter.heroku.com,2005:Article/75572023-07-25T22:45:47Z2023-07-25T22:45:47ZAdd-on Plans and Pricing<p>Add-ons must define one or more associated plans before <a href="https://devcenter.heroku.com/articles/bringing-an-add-on-to-market#advancing-to-ga">advancing from beta to GA</a>. Each plan can specify a different price, including free, along with a different set of available features and usage thresholds.</p>
<h2 id="type-of-billing">Type of Billing</h2>
<p>Add-ons are priced in monthly, flat-rate tiers. Heroku bills customers by the calendar month, and add-on billing is pro-rated according to the amount of time a particular plan was active during the month.</p>
<p>Heroku doesn’t currently support usage-based billing. Enforcement of any plan-specified usage thresholds is the responsibility of the partner.</p>
<p>Commonly, add-ons with usage thresholds respond with a <code>402</code> HTTP status code when a customer attempts to take an action that would exceed their current plan’s associated threshold.</p>
<h2 id="add-a-plan">Add a Plan</h2>
<p>Heroku must approve plans before they’re widely available.</p>
<p>You can create add-on plans in the <a href="https://addons.heroku.com/provider/dashboard">Partner Portal</a>. After creating a plan, it appears with the default availability setting of “Invite Only.”</p>
<p><img src="https://devcenter2.assets.heroku.com/article-images/1528742976-Screen-Shot-2018-06-11-at-11.49.03-AM.png" alt="Screenshot of details for a plan created in the Partner Portal"></p>
<h3 id="plan-availability">Plan Availability</h3>
<p>You can decide which users can access this plan and whether it appears in the Elements marketplace. There are three “availability” states:</p>
<ol>
<li><strong>Invite Only</strong>. You can make the plan available only to specific users and hidden from the marketplace. No additional steps from Heroku required. You add these plans to specific users with “Plan Passes” by adding the users’ email addresses associated with their Heroku account in the Partner Portal.</li>
<li><strong>All Users (hidden)</strong>. You can make the plan available to all users, but hidden from the marketplace. Heroku must change the plan to this state for you.</li>
<li><strong>All Users</strong>. You can make the plan available to all users and visible in the marketplace. Heroku must change the plan to this state for you.</li>
</ol>
<p>For a step-by-step guide on hidden plans and add-on plan summary, look at these slides:
<a href="https://heroku.my.salesforce.com/sfc/p/30000000osTN/a/3A000000Q7ZT/Z31694pZBOj7ZpLgzlZ6tDjNJ22J.RRfkNqf8oWZ2qw">How to Create “Custom” Heroku Add-on Plans</a></p>
<p>To change plan availability, complete the <a href="https://goo.gl/forms/vSNYJYaEJeOuacD73">add-on plan change request intake form</a>.</p>
<h2 id="modifying-add-on-plans">Modifying Add-On Plans</h2>
<p>Heroku must approve any price modifications before plans are widely available.</p>
<h3 id="disabling-plans">Disabling Plans</h3>
<p>Heroku must process and approve plan removals. After disabling a plan, customers can no longer provision it. Customers that already have the disabled plan can remain on that plan until they change it themselves or remove the add-on altogether.</p>
<p>To disable a plan, complete the <a href="https://goo.gl/forms/vSNYJYaEJeOuacD73">add-on plan change request intake form</a>.</p>
<h3 id="changing-plan-prices">Changing Plan Prices</h3>
<p>You can edit plan prices directly in the Partner Portal for add-ons in alpha or beta.</p>
<p>To request a price change to a plan for a GA add-on, submit your request in the <strong><code>Features & Plans</code></strong> tab of the <a href="https://addons.heroku.com/provider/dashboard">Partner Portal</a>.</p>
<div class="note">
<p>You can’t change free ($0.00) plans into paid plans.</p>
</div>
<h4 id="step-by-step-instructions">Step-by-Step Instructions</h4>
<ol>
<li>Go to <strong><code>Features & Plans</code></strong> tab for your add-on in the <a href="https://devcenter.heroku.com/articles/(https:/addons.heroku.com/provider/dashboard)">Partner Portal</a>.</li>
<li>Click the double chevron control beside a plan and click <strong><code>Edit Plan Details</code></strong>.</li>
<li>If the plan is for an alpha or beta add-on, you can edit the price directly.</li>
<li>If the plan is for a GA add-on:
a) Click the <strong><code>Request Price Change</code></strong> button to enter a new price.
b) Enter the new price.
c) Click <strong><code>Request Price Change</code></strong>.</li>
</ol>
<h3 id="price-change-behavior">Price Change Behavior</h3>
<p>If approved, the price change behavior differs depending on when you submit the request and the type of request you make.</p>
<h4 id="for-requests-submitted-before-the-20th-of-the-month">For Requests Submitted <strong>Before the 20th of the Month</strong>:</h4>
<h5 id="price-increase-requests-for-new-customers">Price Increase Requests for New Customers</h5>
<p>The price change takes effect on the first of the following month.</p>
<h5 id="price-increase-requests-for-new-and-existing-customers">Price Increase Requests for New and Existing Customers</h5>
<p>For new customers, the price change takes effect on the first of the following month.
For existing customers, the price change takes effect on the first of the month following the next month.</p>
<h5 id="price-decrease-requests">Price Decrease Requests</h5>
<p>The price change takes effect on the first of the following month for both new and existing customers.</p>
<h4 id="for-requests-submitted-on-or-after-the-20th-of-the-month">For Requests Submitted <strong>on or After the 20th of the Month</strong>:</h4>
<p>All new price effective dates shift to one month later than the ones described for (requests submitted before the 20th of the month](#for-requests-submitted-before-the-20th-of-the-month).</p>
<h5 id="price-change-behavior-examples">Price Change Behavior Examples</h5>
<table><thead>
<tr>
<th>Price change</th>
<th>Date request submitted</th>
<th>Applies to new customers</th>
<th>Applies to existing customers</th>
<th>Date new price takes effect for new customers</th>
<th>Date new price takes effect for existing customers</th>
</tr>
</thead><tbody>
<tr>
<td>Increase</td>
<td>11/13/2020</td>
<td>Yes</td>
<td>No</td>
<td>12/1/2020</td>
<td>N/A</td>
</tr>
<tr>
<td>Increase</td>
<td>11/21/2020</td>
<td>Yes</td>
<td>No</td>
<td>1/1/2021</td>
<td>N/A</td>
</tr>
<tr>
<td>Increase</td>
<td>11/13/2020</td>
<td>Yes</td>
<td>Yes</td>
<td>12/1/2020</td>
<td>1/1/2021</td>
</tr>
<tr>
<td>Increase</td>
<td>11/21/2020</td>
<td>Yes</td>
<td>Yes</td>
<td>1/1/2021</td>
<td>2/1/2021</td>
</tr>
<tr>
<td>Decrease</td>
<td>11/13/2020</td>
<td>Yes</td>
<td>Yes</td>
<td>12/1/2020</td>
<td>12/1/2020</td>
</tr>
<tr>
<td>Decrease</td>
<td>11/21/2020</td>
<td>Yes</td>
<td>Yes</td>
<td>1/1/2021</td>
<td>1/1/2021</td>
</tr>
</tbody></table>tag:devcenter.heroku.com,2005:Article/75582023-06-06T15:47:22Z2023-11-09T19:18:46ZHeroku Brand Guidelines<p>Heroku’s brand identity emphasizes clarity, balance, and craft. We created these guidelines to ensure that our brand maintains a consistent look and feel no matter where it’s experienced. As a company, we continue to question how we can transform process into an enjoyable experience.</p>
<p>If you have any questions about the Heroku brand, get in touch by emailing <a href="mailto:brand@heroku.com">brand@heroku.com</a>.</p>
<h2 id="usage">Usage</h2>
<p>In general, don’t use the Heroku name, logos, or graphics in ways that can confuse, mislead, or suggest our sponsorship, endorsement, or affiliation.</p>
<h3 id="names-and-logos">Names and Logos</h3>
<p>The Heroku trademark is a proper adjective. Don’t modify the spelling or structure. For example, don’t use “Heroku’s” or “Heroku-ish”.</p>
<p>Don’t use a domain name containing “heroku” or any similar words.</p>
<p>Don’t use “Heroku” as a part of your name or incorporate the Heroku logo into yours. See <a href="#logos">Logos</a> for logo and logotype files and info.</p>
<h4 id="promotional-materials">Promotional Materials</h4>
<p>Contact <a href="mailto:brand@heroku.com">brand@heroku.com</a> before using the Heroku logo on websites, products, packaging, manuals, or for other commercial or product use.</p>
<h4 id="linking-to-heroku">Linking to Heroku</h4>
<p>You can use the Heroku logo or name to link to our site, as long as your usage meets the guidelines within this document. For text links, capitalize “Heroku”, and use “heroku.com” when referring to our URL.</p>
<h4 id="merchandise-and-swag">Merchandise and Swag</h4>
<p>While we do produce t-shirts and other items with the Heroku logo and artwork, we don’t generally allow third parties to make, sell, or give away anything with our name or logo on it.</p>
<h4 id="education-and-instructional">Education and Instructional</h4>
<p>You can use Heroku branded materials for educational and instructional purposes. Remember they must not confuse, mislead, or suggest our sponsorship.</p>
<h2 id="logos">Logos</h2>
<p>The triangular shape within our logo symbolizes the straightforward and clear experience of the familiar play button.</p>
<h3 id="style-options">Style Options</h3>
<p>The Heroku logo is often the first visual experience with the Heroku brand. Download the full <a href="https://devcenter3.assets.heroku.com/article-images/Heroku-Logos-20231108T211445Z-001.zip">logo kit</a> to see all the options. We designed these options to feel cohesive, yet distinct enough for use in any placement.</p>
<h4 id="stroke-and-solid-logos">Stroke and Solid Logos</h4>
<p>Use our logo when the context of Heroku is clear and established. Works well in any layout.</p>
<p><img src="https://devcenter3.assets.heroku.com/article-images/1685983850-Screenshot-2023-06-05-at-12.50.38-PM.png" alt="Heroku purple stroke logo (left) and purple solid logo (right)"></p>
<p>The stroke logo on the left is our primary brand mark. It looks best on simple backgrounds.</p>
<p>Use the solid logo occasionally for prominence or on busy backgrounds.</p>
<h4 id="logotypes">Logotypes</h4>
<p>Use a logotype to establish the context of Heroku, or to represent Heroku alongside third-party logos.</p>
<p><img src="https://devcenter3.assets.heroku.com/article-images/1685984734-Screenshot-2023-06-05-at-1.05.26-PM.png" alt="Heroku purple vertical (left) and horizontal (right) logotypes"></p>
<p>Our vertical logotype is our preferred option, suiting centered layouts and use when width is limited.</p>
<p>Use the horizontal logotype sparingly, in left-aligned layouts or when height is limited.</p>
<h3 id="color-options">Color Options</h3>
<p>We provide the Heroku logo and logotype in a few colors so that placement feels integrated and cohesive.</p>
<p><img src="https://devcenter3.assets.heroku.com/article-images/1685988073-Screenshot-2023-06-05-at-2.00.52-PM.png" alt="Heroku logos in purple, white, gradient and black from left to right"></p>
<p>Purple is our main color. Use this version where possible. It works best on white or light backgrounds.</p>
<p>Use white for dark backgrounds, and occasionally as a translucent overlay.</p>
<p>Use a gradient on dark backgrounds to reinforce brand and depth. Often used in presentations and event signage.</p>
<p>Use black as a translucent overlay for light, solid backgrounds. It’s best when other logos in the graphic get similar treatment.</p>
<h3 id="spacing">Spacing</h3>
<p>Leave 50% of the width of the Heroku logo on each side. No additional text, unicorns, or other elements can appear within this space.</p>
<p>Scaling our logo is reliable and crisp in many sizes. Scale in multiples of 2 or 4. The stroke surrounding our logo is 50% of the weight of the logo. The overall dimensions and interior whitespace are proportionately equivalent to multiples of 2, 4, and 8.</p>
<p><img src="https://devcenter0.assets.heroku.com/article-images/1685988302-Screenshot-2023-06-05-at-2.04.50-PM.png" alt="Dimensions for the Heroku logo, vertical logotype and horizontal logotype, from left to right"></p>
<h3 id="built-on-heroku">Built on Heroku</h3>
<p>You can show that you built your app on Heroku with these badges. There are two options for you to download: <a href="https://devcenter3.assets.heroku.com/article-images/built-on-heroku-dark-on-light.zip">dark on light</a>, or <a href="https://devcenter3.assets.heroku.com/article-images/built-on-heroku-light-on-dark.zip">light on dark</a>.</p>
<p><img src="https://devcenter2.assets.heroku.com/article-images/1685988561-Screenshot-2023-06-05-at-2.09.11-PM.png" alt="Built on Heroku badges, dark on light and light on dark"></p>
<p>Link the badge to <a href="https://heroku.com/">heroku.com</a>. Adjust the opacity and size within legible limits, and maintain a style that supports your brand and ours.</p>
<h3 id="logo-misuse-examples">Logo Misuse Examples</h3>
<p>Use the <a href="https://devcenter3.assets.heroku.com/article-images/Heroku-Logos-20231108T211445Z-001.zip">logos as provided</a>. Heroku encourages creative application development, not creative use of lens flare.</p>
<p>Placing any graphic or logo can prove challenging in some layouts or designs. If you encounter any instances of misuse, contact <a href="mailto:brand@heroku.com">brand@heroku.com</a>.</p>
<p>These examples represent just a few ways that modifications to our logo can misrepresent Heroku:</p>
<ul>
<li>Distortion</li>
<li>Added text</li>
<li>Rotation</li>
<li>Colorization</li>
<li>Added outlines</li>
<li>No boundaries</li>
<li>Using the wrong colors</li>
<li>Always using purple, even on poorly contrasted backgrounds</li>
</ul>
<p><img src="https://devcenter1.assets.heroku.com/article-images/1685988759-Screenshot-2023-06-05-at-2.12.32-PM.png" alt="Heroku logo misuse examples of distortion, additional text, rotation and colorization"></p>
<p><img src="https://devcenter0.assets.heroku.com/article-images/1685988859-Screenshot-2023-06-05-at-2.14.11-PM.png" alt="Heroku logo misuse examples of outlines, boundaries, multiple misuses and always using purple"></p>
<h2 id="color">Color</h2>
<h3 id="purple">Purple</h3>
<p>Purple is the main color of the Heroku brand. In its many shades and hues, we appreciate purple’s depth, distinction, and balance of warm and cool.</p>
<p>Varying shades and hues bring harmony to a design, helping it feel natural, organic, and human, rather than calculated and mechanical.</p>
<p><img src="https://devcenter3.assets.heroku.com/article-images/1685989811-Screenshot-2023-06-05-at-2.30.04-PM.png" alt="Indigo, Violet and Lavender color swatches"></p>
<p>For backgrounds, illustrations, and gradients, use indigo #211746, <a href="https://pantone.com/color-finder/275-C">Pantone 275 C</a>.</p>
<p>For headings, staff t-shirts, and illustrations, use violet #430098, <a href="https://pantone.com/color-finder/Violet-C">Pantone Violet C</a>.</p>
<p>For highlights, dark backgrounds, and illustrations, use lavender #7673C0, <a href="https://pantone.com/color-finder/272-C">Pantone 272 C</a>.</p>
<h3 id="gray">Gray</h3>
<p>Gray offsets our distinctive purple with an understated calm. In text, on screen, in graphics, and beyond, gray is easygoing and adaptable.</p>
<p>When using the Heroku color palette in your designs, adjust the shade or brightness of a color so that it’s cohesive with your work.</p>
<p><img src="https://devcenter3.assets.heroku.com/article-images/1685990477-Screenshot-2023-06-05-at-2.41.09-PM.png" alt="Asphalt, Mineral and Storm color swatches"></p>
<p>For backgrounds, illustrations, and gradients, use asphalt #333D47, <a href="https://pantone.com/color-finder/432-C">Pantone 432 C</a>.</p>
<p>For headings, staff t-shirts, and illustrations, use mineral #7C858C, <a href="https://pantone.com/color-finder/430-C">Pantone 430 C</a>.</p>
<p>For highlights, dark backgrounds, and illustrations, use storm #C3C5C8, <a href="https://pantone.com/color-finder/428-C">Pantone 428 C</a>.</p>
<h3 id="blue">Blue</h3>
<p>Beyond our shades of purple and gray, we use blue both as a highlight and as a link to Salesforce.</p>
<p>Heroku is a Salesforce company. The Salesforce Blue is an important part of our identity, drawing inspiration from day and night skies.</p>
<p><img src="https://devcenter3.assets.heroku.com/article-images/1685990749-Screenshot-2023-06-05-at-2.45.41-PM.png" alt="Salesforce Blue, Mid Blue and Dark Blue color swatches"></p>
<p>For the Salesforce logo, and for gradients with the Heroku purple, use Salesforce Blue #00A1E0, <a href="https://pantone.com/color-finder/299-C">Pantone 299 C</a>.</p>
<p>For backgrounds, use mid blue #215CA0, <a href="https://pantone.com/color-finder/661-C">Pantone 661 C</a>.</p>
<p>For darker backgrounds, use dark blue #032E61, <a href="https://pantone.com/color-finder/280-C">Pantone 280 C</a>.</p>
<h3 id="digital-palette">Digital Palette</h3>
<p>Our digital properties use a mixed palette of brand and primary colors, shades, and gradients. From UI elements to detailed illustrations, they’re at the heart of our products.</p>
<h4 id="colors">Colors</h4>
<p><img src="https://devcenter3.assets.heroku.com/article-images/1685990921-Screenshot-2023-06-05-at-2.48.34-PM.png" alt="Color swatches"></p>
<h4 id="shades">Shades</h4>
<p><img src="https://devcenter1.assets.heroku.com/article-images/1685990995-Screenshot-2023-06-05-at-2.49.03-PM.png" alt="Shade swatches"></p>
<h4 id="gradients">Gradients</h4>
<p><img src="https://devcenter1.assets.heroku.com/article-images/1685990999-Screenshot-2023-06-05-at-2.49.11-PM.png" alt="Gradient swatches"></p>
<h2 id="type">Type</h2>
<h3 id="benton-sans">Benton Sans</h3>
<p>Benton Sans is the main font of Heroku. We appreciate its elegance, flexibility, and legibility. It’s available in many weights, making it versatile for both print and screen.</p>
<div class="callout">
<p>Designed by Morris Fuller Benton in 1908, News Gothic became a 20th century standard. In 1995, Tobias Frere-Jones began a redesign that was expanded into Benton Sans by Cyrus Highsmith and the Font Bureau studio.</p>
</div>
<p><img src="https://devcenter3.assets.heroku.com/article-images/1685991223-Screenshot-2023-06-05-at-2.52.22-PM.png" alt="Benton Sans example"></p>
<h3 id="inconsolata">Inconsolata</h3>
<p>Inconsolata is fixed-width for displaying code. With a similar two-story “a” and “g”, it pairs well with Benton Sans, looks sharp in small sizes, and is easy to read on the command line. You can <a href="https://fonts.google.com/specimen/Inconsolata">download the font here</a>.</p>
<div class="callout">
<p>Designed by Raph Levien, Inconsolata is a humanist sans inspired in part by Adrian Frutiger’s Avenir, and Morris Fuller Benton’s Franklin Gothic. Inconsolata is available freely with an Open Font License.</p>
</div>
<p><img src="https://devcenter0.assets.heroku.com/article-images/1685991226-Screenshot-2023-06-05-at-2.52.27-PM.png" alt="Inconsolata example"></p>
<h2 id="contact">Contact</h2>
<p>If you have any questions about the Heroku brand, get in touch by emailing <a href="mailto:brand@heroku.com">brand@heroku.com</a>.</p>