Processes
On Heroku an app is a set of process types declared in a Procfile, each run on one or more dynos. Tapitalee has the same shape: an app has one or more Processes, each running one or more containers on ECS Fargate.
Concept mapping
| Heroku | Tapitalee | Notes |
|---|---|---|
web process type |
default process |
Created with the app. The only process that is reachable from the internet. |
worker, clock, other process types |
Additional processes (tapit create process name=worker ...) |
Private, background only. Named alphanumeric with hyphens. |
| Dyno | Container (Fargate task) | One running instance of a process. |
| Dyno size | cpu (vCPUs) and memory (GB) per process |
Set independently, e.g. cpu=1 memory=2. |
| Dyno count | demand_count and spot_count |
Total containers = demand + spot. |
| Autoscaling (Performance dynos) | scale_type, scale_count, autoscaling_cpu_threshold |
CPU-based, adds scale_count extra spot or demand containers. |
heroku ps:stop / scale to 0 |
disabled=true |
Preserves counts so you can turn it back on. |
release: process type |
Pre-deploy steps | Ordered commands run before the deploy completes. |
One-off dyno (heroku run) |
Task or console session (tapit run) |
Fresh ephemeral container each time. |
| Heroku Scheduler add-on | Scheduled commands | Full cron expressions. |
$PORT |
$PORT |
Injected into the default process, same convention. |
| Dyno cycling every 24h | None | Containers run until you deploy, restart or disable them. |
| Preboot | Default behaviour | New containers must pass optional health checks before old ones stop. Deployments only proceed if all predeploy steps succeed - this can be used to ensure the new copy of hte app boots before the deploy itself. |
The Procfile
Heroku started each dyno with the command from the Procfile. Tapitalee starts a container with the image’s default command, and a process may override it with command=.
- Buildpack builds:
tapit image deployuses Cloud Native Buildpacks, which read theProcfileand make thewebentry the image’s default command. So thedefaultprocess runs yourweb:line unchanged. - Dockerfile builds: the image
CMD/ENTRYPOINTis what thedefaultprocess runs. - Other process types: create a process per Procfile entry and put the command in
command=.
Given this Heroku Procfile:
web: bundle exec puma -C config/puma.rb
worker: bundle exec sidekiq
release: bundle exec rails db:migrate
The Tapitalee equivalent is:
# web -> default process, created with the app; runs the image default command
tapit create app myapp cpu=0.5 memory=1 demand=2
# worker -> a private process with the command from the Procfile
tapit create process name=worker command="bundle exec sidekiq" cpu=0.5 memory=1 demand_count=1
# release -> a command registered as a pre-deploy step
tapit create command name=migrate 'bundle exec rails db:migrate'
tapit create predeploy_step name=migrate
command= is a plain shell command, so bundle exec sidekiq -q critical -q default works as written.
Ports and the web process
Like Heroku, your web server must listen on the port in the PORT environment variable. The default process port defaults to 80 and is configurable in the process settings; PORT is set to match. See Webserving for how traffic reaches the default process and why a proxy add-on is recommended.
Heroku terminated TLS at its router and forwarded plain HTTP with X-Forwarded-Proto. Tapitalee’s SecureProxy and CertWrapper add-ons do the same, so config.force_ssl, trust proxy settings and similar continue to work.
Dyno sizes to cpu / memory
There is no fixed list of sizes. Pick any Fargate-supported vCPU/GB combination per process. Rough starting points:
| Heroku dyno | Suggested cpu / memory |
|---|---|
| Eco / Basic / Standard-1X (512 MB) | cpu=0.25 memory=0.5 (the default) |
| Standard-2X (1 GB) | cpu=0.5 memory=1 |
| Performance-M (2.5 GB) | cpu=1 memory=2 or memory=3 |
| Performance-L (14 GB) | cpu=4 memory=16 |
Heroku dyno CPU was shared and bursty; Fargate vCPUs are dedicated, so you can often run smaller. Use tapit show metrics process=default to check utilisation after moving.
Scaling
# heroku ps:scale web=3 worker=2
tapit set process name=default demand_count=3
tapit set process name=worker demand_count=1 spot_count=1
# heroku ps:resize web=performance-m
tapit set process name=default cpu=1 memory=2
# heroku ps:restart worker
tapit restart process name=worker
# heroku ps:stop worker / heroku ps:scale worker=0
tapit set process name=worker disabled=true
Spot containers (spot_count) have no Heroku equivalent: they cost about a third of on-demand but can be interrupted, which suits workers and queue consumers. See On-Demand vs Spot.
Autoscaling replaces Heroku’s response-time based autoscaling with a CPU threshold:
tapit set process name=default scale_type=demand scale_count=2 autoscaling_cpu_threshold=70
Release phase to pre-deploy steps
Heroku’s release: command ran once per release, before the new release received traffic, and a non-zero exit aborted it. Tapitalee pre-deploy steps behave the same way, with two differences:
- They are commands you define once and can also run manually or on a schedule.
- You can have several, run in order. Deploy is aborted and the app stays on the previous version if any fails.
tapit create command name=migrate 'bundle exec rails db:migrate'
tapit create predeploy_step name=migrate
tapit list predeploy_steps
Migration output is in the task logs: tapit list tasks -all then tapit show logs task=<name>. A deploy can skip them with skip_predeploy_steps=true.
One-off dynos to tasks and consoles
| Heroku | Tapitalee |
|---|---|
heroku run bash |
tapit run bash |
heroku run rails console |
tapit run 'rails console' |
heroku run:detached rake reports:nightly |
tapit create task 'rake reports:nightly' |
heroku run --size=performance-l ... |
tapit run bash cpu=4 memory=16 |
heroku ps (one-off dynos listed) |
tapit list tasks, tapit list processes |
heroku ps:stop run.1234 |
tapit delete task task=<name> |
heroku logs --dyno run.1234 |
tapit show logs task=<name> |
Both run in a fresh container from the currently deployed image (or docker_tag=/image= to choose another) with all variables and add-on connections available, exactly like a one-off dyno. Tasks default to 1 vCPU / 2 GB and are killed after max_hours (48 by default). Interactive sessions need bash and curl in the image. See Console Access and Tasks.
Heroku Scheduler to scheduled commands
Heroku Scheduler offered every 10 minutes, hourly or daily. Tapitalee commands accept any cron expression and record their run history:
# Scheduler job: "rake cleanup" daily at 02:00 UTC
tapit create command name=cleanup 'rake cleanup' schedule='0 2 * * *'
# Scheduler job: every 10 minutes
tapit create command name=poll 'python poll.py' schedule='*/10 * * * *' cpu=0.25 memory=0.5
tapit list commands
tapit set command name=cleanup schedule='0 3 * * *'
If you replaced Scheduler with a clock process (e.g. the clockwork gem or celery beat), keep it as a process with demand_count=1, or convert its jobs to scheduled commands and drop the always-on container.
Logs and metrics
# heroku logs --tail
tapit show logs -f
# heroku logs --ps worker
tapit show logs process=worker
# heroku logs -n 1000 --source app | grep ERROR
tapit show logs limit=1000 filter=ERROR
# Heroku metrics tab
tapit show metrics process=default interval=24h
Logs are in CloudWatch Logs in your account. Log drains have no direct equivalent; use the Datadog add-on for forwarding, or read CloudWatch directly. See Logs & Metrics.