# `fly`-ing `huginn` close to the ground
konami are remaking MGS3. some people are trying to sell [electric ekranoplans](https://www.regentcraft.com/seagliders/viceroy#specifications). and
here i am being a freeloader nerd for the 2nd decade. ingredients:
- [huginn/huginn image](https://ghcr.io/huginn/huginn) (sponsor [co-author & maintainer knu](https://github.com/sponsors/knu))
- [sentry DSN](https://sentry.io/pricing/) and/or [GlitchTip](https://glitchtip.com/pricing) ([donation page](https://liberapay.com/GlitchTip/donate))
- [fly.io dashboard](https://fly.io/docs/about/pricing/)
- [inoreader](https://jp.inoreader.com/pricing) and/or [feedly](https://feedly.com/i/pro) and/or [feedbin](https://feedbin.com/)
i use its agent to crawl comic/blogs' syndication feeds, then reformat & augment them to read easily in [feedme](https://github.com/seazon/feedme). The comics update at most daily ([SMBC](https://www.smbc-comics.com/comic/archive) has been running since 2002), or thrice-weekly (Ryan North's [dinosaurs](https://qwantz.com/index.php?comic=1) have been talkin' since 2003 (lovingly crafted in [XP's MS Paint](https://www.qwantz.com/index.php?comic=4005)). and the blogs update less frequently than that. there's no need to keep huginn web-part running 24/7, and we can also reduce the scheduler wake-up frequency.
## Getting `flyctl` on MediaTek ramips mt7621
it's a softfloat Little-Endian MIPS cpu, we'll build `flyctl` like this:
```shell
scalar clone http://github.com/superfly/flyctl
cd flyctl/src
git sparse-checkout disable
env GOARCH=mipsle GOMIPS=softfloat make build
gzip bin/flyctl
# deliver flyctl.gz to the mips
```
## Making sentry crons and/or glitchtip uptime monitor
on sentry, SMBC will have a daily check-in schedule. Dinosaur Comics posts on Mon-Wed-Fri, accounting for TZ & scheduling delay, we'll have a Tue-Thu-Sat check-in regimen. both will allow some further ~2h slack time. the monitoring slugs are readable text now, not UUIDv4 anymore. but that's guessable. along with the project's `SENTRY_DSN` and quickstart for rails, we're good to go.
on glitchtip, set up a 86399-second interval uptime heartbeat (they don't accept >=86400s). we'll use the URL later.
## Launch pad
we start simple with the `supervisord`-based image. that'd keep a 1GB fly machine running all the time.
Fly people use docker images as a packaging format, they define the
environment around that. here, we bake in postgresql and the sentry
SDK gems. remember to [load `stackprof` first](https://docs.sentry.io/platforms/ruby/profiling/#enable-profiling):
```bash
mkdir hug
cd hug
echo -e '.dockerignore\nDockerfile\nfly.toml\nhug-db.toml\nsentry.rb' | tee .dockerignore
tee Dockerfile <<-EOD
FROM ghcr.io/huginn/huginn:cbeb5c293ec3394dcd202b132b80e14398da8a11
ENV ADDITIONAL_GEMS=stackprof,sentry-ruby,sentry-rails
RUN APP_SECRET_TOKEN=nbd DATABASE_ADAPTER=postgresql bundle install -j 4
# we tune this often
COPY sentry.rb /app/config/initializers/sentry.rb
EOD
tee sentry.rb <<-EOR
Sentry.init do |config|
config.breadcrumbs_logger = [:active_support_logger, :http_logger]
config.traces_sample_rate = 0.5
config.profiles_sample_rate = 1.0
end
EOR
```
generate random for `APP_SECRET_TOKEN`:
```sh
podman run --rm -it --entrypoint sh ghcr.io/huginn/huginn:cbeb5c293ec3394dcd202b132b80e14398da8a11 rake secret
```
Build initial fly config, along with a managed postgres:
```bash
flyctl launch \
--org personal \
--name hug \
--region fra \
--push \
--vm-cpukind shared \
--vm-cpus 1 \
--vm-memory 1024
```
for the postgres, you can use development, 256MB, auto scale to zero (default after 1h, but [you can be more aggressive/conservative](https://fly.io/docs/postgres/managing/scale-to-zero/#turn-off-the-scale-to-zero-feature)). let's write down its config file here too:
```bash
flyctl config save \
--app hug-db \
--config hug-db.toml
```
and it's a good idea to save the running postgres image for later use:
```bash
flyctl image show -a hug-db
```
load some more secrets into the app:
```bash
flyctl secrets import <<-EOS
SENTRY_DSN=your_dsn
APP_SECRET_TOKEN=your_random
INVITATION_CODE=your_knock_password
EOS
```
and put more app config
```bash
tee -a fly.toml <<-EOT
[[statics]]
guest_path = "/app/public"
url_prefix = "/public"
[env]
RAILS_SERVE_STATIC_FILES="false"
TIMEZONE="Hanoi"
TZ="Asia/Phnom_Penh"
DOMAIN="hug.fly.dev"
FORCE_SSL="true"
DATABASE_ADAPTER="postgresql"
RACK_ENV="production"
RAILS_LOG_TO_STDOUT="enabled"
DO_NOT_SEED="true"
IMPORT_DEFAULT_SCENARIO_FOR_ALL_USERS="true"
AGENT_LOG_LENGTH="10" # used to fit heroku 10_000 rows limit
SCHEDULER_FREQUENCY="5"
DELAYED_JOB_SLEEP_DELAY="900" # s
USE_GRAPHVIZ_DOT="dot"
DIAGRAM_DEFAULT_LAYOUT="neato"
EOT
```
now you try to `flyctl launch` it, see the resulting 2.0GB image starts on fly regino `fra`
if you get context deadline exceeded for build, try wesockets mode
```bash
flyctl wg websockets enable
```
to attach in for debugging
```bash
flyctl ssh console -s
```
in there, multi-process img has `pstree` to view supervisor's tree
and tail the logs
```bash
flyctl logs
```
here, you can open the public URL, and create an account with the invitation code. there's no `admin` account because we didn't run SEED job. huginn will have created sample agents for you, explore them for idea
## Split out the workers
The current vm resource is
```bash
flyctl machine show
```
Inside the one machine for `app` process group, there's supervisord, then foreman, managing an unicorn `web.1` (master + 2workers), and the rufus scheduler `jobs.1` task. the unicorn is only useful when i open the site, or inoreader comes to fetch the feed. rufus should be running all the time, to execute scheduled tasks (agents, events propagation, and cleanups). Let's split out `app` to `web` and `jobs`, then we can let web autostop/start according to load.