How to edit files in a Heroku dyno and persist it
Tags: heroku, slug, dyno, file
Published: 2019-11-11 16:08:13

If you edit files present in a Heroku dyno, the edited file comes back to its initial state after some time. This is because Heroku restarts the dynos randomly for keeping them in good health.

# Heroku Deployment Process:

[skip this](#editing-slug) if you are familiar

1. Initiating deployment:
 * Heroku deployment can be triggered manually or it can be configured to get triggered automatically by connecting Heroku to GitHub.
2. During deployment: 
 * Heroku builds the application based on default settings or based on the configured build packs.
 * At the end of this process, a slug will be created. A slug is nothing but the files that were generated during the build. A slug is similar to a docker image (not exactly).
3. The created slug is deployed in AWS EC2 instances, which is called as dynos by Heroku.
4. At random intervals, the slug is redeployed for maintaining the health of the dynos [#ref](https://devcenter.heroku.com/articles/dynos#automatic-dyno-restarts)

> 👆This is the reason why files edited in a dyno will be reset to its initial state.


👻
### So, How can we make changes to the files in a Heroku dyno which does not reset to its previous version?

One straightforward solution is to make the changes in the source code and redeploy the application.

Yes, this is one way of achieving it.

But, You may wonder why there would be another scenario. One rare scenario is: _You want to change a HTML file (urgent client requirement) that is already part of an application in the production environment, but your build process is getting timed out and you are not able to find the reason_.

So, The other solution is:
> By editing the previously generated slug and using the edited slug in the required application/environment. <a name="editing-slug"></a>

# Steps to edit the slug and deploy it:
_(100% no build process is required)_
<ol>
<li>Download Heroku CLI
 <ul><li>https://devcenter.heroku.com/articles/heroku-cli#download-and-install</li></ul></li>
<li>Login to your Heroku account using the CLI
 <ul><li>`$ heroku login`</li>
 <li>This will take you to a browser to fill the login form.</li></ul></li>
<li>List all the deployed applications
 <ul><li>`$ heroku list --all`</li></ul></li>
<li>Get the unique slug identifier and version number
 <ul><li>`$ heroku slugs -a your_application_name`</li>
 <li>Use the name of the application which has the files you want to edit.</li>
 <li>You will get all the unique slug identifiers along with their version numbers that are generated and used by your application until now.</li>
 <li>This version number can be verified from the dashboard https://dashboard.heroku.com/apps/your_application_name/activity</li>
 <li>If you have too many deployments, store the list to a file </li>
 <li>`$ heroku slugs -a your_application_name > slugsList.txt`</li></ul></li>
<li>Download the slug
 <ul><li>To download, you need an additional Heroku CLI plugin</li>
 <li>Install the additional plugin using `heroku plugins:install heroku-slugs`</li>
 <li>Then `$ heroku slugs:download your_unique_slug_identifier -a your_application_name`</li>
 <li>This will download and create a folder with the name of your application.</li>
<li>The created folder will contain a directory called `app` which contains the generated source code and a `slug.tar.gz` file, which is the compressed version the source code.</li></ul></li>
<li>Edit the required files present within the `./app` directory.</li>
<li>Create new slug archive
 <ul>
 <li>Heroku currently has limited tar-file compatibility. Please use [GNU Tar](http://www.gnu.org/software/tar/tar.html) (and not `bsdtar`) when creating slug archives. You can check your tar version with `tar --version`. </li>
 <li>While running the below command, you should be in the same directory level as that of `./app` directory.</li>
 <li>`$ tar czfv slug.tgz ./app`</li>
 <li>`slug.tgz` is the name of the archive that will be created</li>
 <li>`c` - create, `z` - gzip format, `v` - show status, `f` - file name and location</li>
</ul></li>
<li>Create a unique identifier for the new slug
<ul><li>```bash
$ curl -X POST \
-H 'Content-Type: application/json' \
-H 'Accept: application/vnd.heroku+json; version=3' \
-d '{"process_types":{"your_process_type":"your_command"}}' \
-n https://api.heroku.com/apps/your_application_name/slugs
```
</li>
<li>If you don't know your process type(s) and the respective commands, then go to https://dashboard.heroku.com/apps/your_application_name/resources
![process types](https://cdn.jsdelivr.net/gh/KrishnaPravin/my-blog-images/How-to-edit-files-in-a-Heroku-dyno-and-persist-it/process-types.png)</li>
 <li>For my application, I have two process types. So I will be sending this data in the API call

`{"process_types":{"web": "bundle exec puma -p $PORT -C ./config/puma.rb", "worker": "bundle exec rake jobs:work"}}`</li>
 <li>`-n` flag tells curl to read the credentials for `api.heroku.com` from `~/.netrc` and automatically sets the `Authorization` header.</li>
 <li>`-H` flag sets the respective header</li>
 <li>`-d` flag represents the data to be sent in HTTP POST request</li>
 <li>You will get a response like this
<ul><li>```json
{
  "blob":{
    "method": "put",
    "url": "https://s3-external-1.amazonaws.com/herokuslugs/heroku.com/v1/d969e0b3-9892-4567-7642-1aa1d1108bc3?AWSAccessKeyId=AKIAJWLOWWHPBWQOPJZQ&Signature=2oJJEtemTp7h0qTH2Q4B2nIUY9w%3D&Expires=1381273352"
  },
  "commit":null,
  "created_at":"2013-10-08T22:04:13Z",
  "id":"d969e0b3-9892-3113-7653-1aa1d1108bc3",
  "process_types":{
    "web":"node-v0.10.20-linux-x64/bin/node web.js"
  },
  "updated_at":"2013-10-08T22:04:13Z"
}
```</li></ul></li>
 <li>`blob.url` - AWS S3 URL for the new slug</li>
 <li>`id` - Unique identifier for the new slug</li>
 <li>[Heroku docs reference](https://devcenter.heroku.com/articles/platform-api-deploying-slugs#publish-to-the-platform)</li></ul></li>
<li>Upload the created slug archive to AWS S3
<ul><li>```bash
$ curl -X PUT \
-H "Content-Type:" \
--data-binary @slug.tgz \
"https://your_aws_s3_blob_url"
```</li>
<li>`slug.tgz` is the name of the archive file we have created.</li></ul></li>
<li>Create a new release for your application which will use the new slug archive which we have created and uploaded to AWS S3
<ul><li>```bash
$ curl -X POST \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Content-Type: application/json" \
-d '{"slug":"your_unique_identifier_of_new_slug"}' \
-n https://api.heroku.com/apps/your_application_name/releases
```</li></ul></li>
> You can verify the release status in the Heroku dashboard or using `heroku releases --app your_application_name`