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 deploy uses Cloud Native Buildpacks, which read the Procfile and make the web entry the image’s default command. So the default process runs your web: line unchanged.
  • Dockerfile builds: the image CMD / ENTRYPOINT is what the default process 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.