Skip to content

Commit

Permalink
articles/fly-io-postgres-read-replica: rewrite to be single file
Browse files Browse the repository at this point in the history
Remove Gemfile, Gemfile.lock, and .solargraph.yml.
  • Loading branch information
croaky committed Dec 5, 2022
1 parent 0c6d1bf commit faa6874
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 193 deletions.
72 changes: 29 additions & 43 deletions articles/fly-io-postgres-read-replica-multi-region-ruby.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,31 @@
# Fly.io Multi-Region Ruby with Postgres Read Replicas

For latency (or, less relevant to this article, data residency) reasons,
For latency reasons,
you might want to deploy your app to a specific region.
[Fly.io has 20+ regions](https://fly.io/docs/reference/regions/)
on their own Points of Presence
(not on public clouds like AWS).
on their own Points of Presence (not on public clouds like AWS).

If you have a read-heavy application, look at Fly's
[multi-region Postgres read replicas](https://fly.io/docs/getting-started/multi-region-databases/).
The big caveat is
[Fly, unlike Heroku, is not managed Postgres](https://fly.io/docs/rails/getting-started/migrate-from-heroku/#databases).
The caveat is
[Fly Postgres is not managed](https://fly.io/docs/rails/getting-started/migrate-from-heroku/#databases).

## Ruby app

In this example, we'll write and deploy a Ruby app to Fly.io using popular gems:

* [Connection Pool](https://rubygems.org/gems/connection_pool)
* [PG](https://rubygems.org/gems/pg)
* [Puma](https://rubygems.org/gems/puma)
* [Sinatra](https://rubygems.org/gems/sinatra)

The `Gemfile` looks like this:

```embed
code/fly-ruby-read-replica/Gemfile all
```

Install the gems:

```bash
bundle
```

The `api.rb` looks like this:
In this example, we'll write and deploy a Ruby app to Fly.io:

```embed
code/fly-ruby-read-replica/api.rb all
code/fly-read-replica/main.rb
```

## Develop

Develop locally:
Run locally:

```bash
bundle
createdb example_dev
DATABASE_URL="postgres:///example_dev" bundle exec ruby api.rb
createdb db
chmod +x main.rb
DATABASE_URL=postgres:///db ./main.rb
```

## Fly
Expand All @@ -62,42 +42,48 @@ Connect to your account:
fly auth login
```

Deploy using Fly's `--remote-only` option,
which will use a remote Docker builder Fly sets up in your account.
If you previously had a Docker installation, avoid
[a gotcha](https://community.fly.io/t/failed-to-fetch-builder-image-when-deploying-ruby-example/3726/7),
by deleting `~/.docker` before you deploy:
If you don't have Docker installed,
use Fly's `--remote-only` option,
which will use a remote Docker builder in your Fly account:

```bash
rm -rf ~/.docker
fly launch --remote-only
```

Configure region where the primary database is:
If you have Docker installed,
deploy with Fly's `--nixpacks` option,
which will use [nixpacks](https://github.com/railwayapp/nixpacks) as the builder.
It deploys faster:

```bash
fly launch --nixpacks
```

Configure region the primary database location,
such as Sunnyvale, California:

```bash
fly secrets set PRIMARY_REGION=sjc
```

Create the regions where the read replicas will go:
Add the regions where the read replicas will go,
such as Frankfurt, Germany and Sydney, Australia:

```bash
fly regions add ams lhr syd yul
fly regions add fra syd
```

Create read replicas in those regions:

```bash
fly volumes create pg_data -a example-read-replicas-db --size 1 --region ams
fly volumes create pg_data -a example-read-replicas-db --size 1 --region lhr
fly volumes create pg_data -a example-read-replicas-db --size 1 --region fra
fly volumes create pg_data -a example-read-replicas-db --size 1 --region syd
fly volumes create pg_data -a example-read-replicas-db --size 1 --region yul
```

Scale 1 instance per region:

```bash
fly autoscale standard min=5 max=5
fly autoscale standard min=3 max=3
```

Done!
27 changes: 22 additions & 5 deletions code/fly-ruby-read-replica/api.rb → code/fly-read-replica/main.rb
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
# begindoc: all
require "connection_pool"
require "pg"
require "sinatra"
#!/usr/bin/env ruby

# createdb db
# chmod +x main.rb
# DATABASE_URL=postgres:///db ./main.rb

require "bundler/inline"

gemfile do
source "https://rubygems.org"

gem "connection_pool"
gem "pg"
gem "puma"
gem "sinatra"

group :development do
gem "standard"
end
end

class DB
def initialize
Expand Down Expand Up @@ -51,4 +67,5 @@ def do_exec(sql)
content_type :json
{status: "ok"}.to_json
end
# enddoc: all

Sinatra::Application.run!
4 changes: 0 additions & 4 deletions code/fly-ruby-read-replica/.solargraph.yml

This file was deleted.

15 changes: 0 additions & 15 deletions code/fly-ruby-read-replica/Gemfile

This file was deleted.

104 changes: 0 additions & 104 deletions code/fly-ruby-read-replica/Gemfile.lock

This file was deleted.

10 changes: 5 additions & 5 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
[
{
"description": "Serve a web app from multiple Fly.io regions and route read requests to Postgres read replicas when possible",
"id": "fly-io-postgres-read-replica-multi-region-ruby",
"updated": "2022-12-05"
},
{
"description": "Pair programmed with OpenAI's ChatGPT",
"id": "heroku-dataclips-clone-in-sinatra",
Expand All @@ -9,11 +14,6 @@
"id": "schedule-deno-builds-with-github-actions",
"updated": "2022-11-23"
},
{
"description": "Serve a web app from multiple Fly.io regions and route read requests to Postgres read replicas when possible",
"id": "fly-io-postgres-read-replica-multi-region-ruby",
"updated": "2022-09-21"
},
{
"description": "Restore a production database into staging and development environments",
"id": "heroku-postgres-restore-staging-development",
Expand Down
47 changes: 30 additions & 17 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@ puts "here"
The lines between magic comments
are embedded back in the original code fence.
To embed the entire file, don't include an ID or magic comments...
```embed
code/example.rb
```
Bad input in the Markdown document or source code file
will stop the program with a non-zero exit code and error text.
*/
Expand Down Expand Up @@ -277,35 +283,42 @@ func preProcess(filepath string) (title, body string) {

if isEmbed {
parts := strings.Split(line, " ")
if len(parts) != 2 {
exitWith("error: embed line must be filepath id like: code/test.rb id")
if len(parts) != 1 && len(parts) != 2 {
exitWith("error: embed line must be filepath id (code/test.rb id) or filepath (code/test.rb)")
}
filename := parts[0]
id := parts[1]

filename := parts[0]
srcCode, err := ioutil.ReadFile(wd + "/" + filename)
check(err)

sep := "begindoc: " + id + "\n"
begindoc := strings.Index(string(srcCode), sep)
if begindoc == -1 {
exitWith("error: embed separator not found " + sep + " in " + filename)
}
// end of comment line
begindoc += len(sep)
begindoc := 0
enddoc := len(srcCode) - 1

if len(parts) == 2 {
id := parts[1]
sep := "begindoc: " + id + "\n"
begindoc := strings.Index(string(srcCode), sep)
if begindoc == -1 {
exitWith("error: embed separator not found " + sep + " in " + filename)
}
// end of comment line
begindoc += len(sep)

sep = "enddoc: " + id
enddoc := strings.Index(string(srcCode), sep)
if enddoc == -1 {
exitWith("error: embed separator not found " + sep + " in " + filename)
sep = "enddoc: " + id
enddoc := strings.Index(string(srcCode), sep)
if enddoc == -1 {
exitWith("error: embed separator not found " + sep + " in " + filename)
}
// backtrack to last newline to cut out comment character(s)
enddoc = strings.LastIndex(string(srcCode[0:enddoc]), "\n")
}
// backtrack to last newline to cut out comment character(s)
enddoc = strings.LastIndex(string(srcCode[0:enddoc]), "\n")

rawLines := strings.Split(string(srcCode[begindoc:enddoc]), "\n")

leadingWhitespace := regexp.MustCompile("(?m)(^[ \t]*)(?:[^ \t])")
var margin string
var lines []string

for i, l := range rawLines {
if i == 0 {
margin = leadingWhitespace.FindAllStringSubmatch(l, -1)[0][1]
Expand Down

0 comments on commit faa6874

Please sign in to comment.