From a78ca47ecc1ffec6e4e842e4c0ad4781b9b508be Mon Sep 17 00:00:00 2001 From: Sam Ruby Date: Wed, 14 Aug 2024 21:15:15 -0400 Subject: [PATCH 1/3] first draft of "happy path" content based on web-dictaphone --- happy-path/aim.html.markerb | 34 +++++++++++++++++++++++++++++ happy-path/application.html.markerb | 23 +++++++++++++++++++ happy-path/fire.html.markerb | 32 +++++++++++++++++++++++++++ happy-path/index.html.markerb | 33 ++++++++++++++++++++++++++++ happy-path/postgresql.html.markerb | 14 ++++++++++++ happy-path/ready.html.markerb | 21 ++++++++++++++++++ happy-path/recap.html.markerb | 25 +++++++++++++++++++++ happy-path/redis.html.markerb | 12 ++++++++++ happy-path/tigris.html.markerb | 9 ++++++++ happy-path/whisper.html.markerb | 25 +++++++++++++++++++++ 10 files changed, 228 insertions(+) create mode 100644 happy-path/aim.html.markerb create mode 100644 happy-path/application.html.markerb create mode 100644 happy-path/fire.html.markerb create mode 100644 happy-path/index.html.markerb create mode 100644 happy-path/postgresql.html.markerb create mode 100644 happy-path/ready.html.markerb create mode 100644 happy-path/recap.html.markerb create mode 100644 happy-path/redis.html.markerb create mode 100644 happy-path/tigris.html.markerb create mode 100644 happy-path/whisper.html.markerb diff --git a/happy-path/aim.html.markerb b/happy-path/aim.html.markerb new file mode 100644 index 0000000000..c74d984172 --- /dev/null +++ b/happy-path/aim.html.markerb @@ -0,0 +1,34 @@ +--- +title: Aim +layout: framework_docs_overview +order: 2 +--- + +For this demo, we will start with [MDN's Web Dictaphone](https://github.com/mdn/dom-examples/tree/main/media/web-dictaphone#web-dictaphone). +You can play with a [live demo](https://mdn.github.io/dom-examples/media/web-dictaphone/). This is about as basic of an +HTML form as you can get, and it has the added bonus of providing the ability to generate as many media files as you want using only your voice. + +Your app undoubtely has many forms, and more complex forms, but once you can see the basic flow, the rest should be easy. + +That demo as it currently stands is client side only, so to deploy it all you need is a web server that can deploy static assets (HTML, CSS, JS, images), +like NGINX, Apache HTTPd, or Caddy. In order to store the data in databases, we are going to need a server that can handle HTTP GET, POST, PUT, and DELETE requests. + +This demo application will come in two flavors. For Node.js, we will select [Express.JS](https://expressjs.com/), and for Rails we will use [Puma](https://github.com/puma/puma). + +* The names of the clips will go into a [PostgreSQL](https://www.postgresql.org/) relational database. +* The audio files themselves will be placed into a [Tigris bucket](https://www.tigrisdata.com/). +* For Node.js, the bulk of this code is in [app.js](https://github.com/fly-apps/node-dictaphone/blob/main/app.js). For Rails, +[app/controller/clipController.rb](https://github.com/fly-apps/rails-dictaphone/blob/main/app/controllers/clips_controller.rb). + +To satisfy the realtime requirement, we will need [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) +and [Upstash for Redis](https://fly.io/docs/reference/redis/). The Node.js implementation is in [pubsub.js](https://github.com/fly-apps/node-dictaphone/blob/main/pubsub.js). +For Rails, the heavy lifting is done by [ActionCable](https://guides.rubyonrails.org/action_cable_overview.html), so all that is needed is +one line in [app/models/clip.rb](https://github.com/fly-apps/rails-dictaphone/blob/6bdf4f639640c9fb55530546dbbed682b65a7df9/app/models/clip.rb#L2) +and one line in [app/views/layouts/application.html.erb](https://github.com/fly-apps/rails-dictaphone/blob/6bdf4f639640c9fb55530546dbbed682b65a7df9/app/views/layouts/application.html.erb#L9). + +The important thing to note is that this is all very straightforward stuff using industry standard components that you can run on your laptop, a VPS, AWS EC2, Google Compute Engine, or Azure. + +If you want to see this up and running on fly.io (and certainly you do or why else would you be here?), all you need +is an empty directory and either Node or Ruby installed. + +Now that we know what we are intending to accomplish, let's proceed to the exciting step: [Fire!](../fire/) diff --git a/happy-path/application.html.markerb b/happy-path/application.html.markerb new file mode 100644 index 0000000000..b52ee41a4b --- /dev/null +++ b/happy-path/application.html.markerb @@ -0,0 +1,23 @@ +--- +title: Your Application +layout: framework_docs_overview +order: 4 +--- + +Your application is running by default on two [Machines](https://fly.io/docs/machines/). + +Don't worry about cost. Both machines stop when not in use, and [autostart](https://fly.io/docs/launch/autostop-autostart/) when a new request comes in. +This is entirely configurable. You can chose to [suspend](https://community.fly.io/t/new-feature-in-preview-suspend-resume-for-machines/20672) instead of stop, +configure a [minimum number](https://fly.io/docs/reference/configuration/#the-http_service-section) of machines to leave running, or even decide never to +stop at all. + +Familiarize yourself with [fly.toml](https://fly.io/docs/reference/configuration/). Make a change there -- or in fact to any part of your application -- and run `fly deploy`. + +The purpose of two machines is twofold: redundancy and scalability. If the machine hosting one goes down, the other can continue on. If both are available, in times of high use both can be started to handle requests. +You can [vertically scale](https://fly.io/docs/launch/scale-machine/) the CPU and RAM on each machine. + +You can also [horizontally scale](https://fly.io/docs/launch/scale-count/) to more machines. Be sure to scroll down on that page far enough to see how to scale to +multiple [regions](https://fly.io/docs/reference/regions/). If you have a co-worker on another continent, create a machine there. + +And all this is made possible by [Anycast](https://fly.io/docs/networking/services/), a [load balancing proxy](https://fly.io/docs/reference/fly-proxy/), and [DNS certificates](https://fly.io/docs/networking/custom-domain/). +Be sure to read the last link if you are interested in custom domains. diff --git a/happy-path/fire.html.markerb b/happy-path/fire.html.markerb new file mode 100644 index 0000000000..9775fd70bc --- /dev/null +++ b/happy-path/fire.html.markerb @@ -0,0 +1,32 @@ +--- +title: Fire +layout: framework_docs_overview +order: 3 +--- + +This is the point where the rubber meets the road, so this is where you would expect to see where the marketing hype promised by [Speedrun](https://fly.io/speedrun) and +the [Quick Start](../getting-started/launch/) don't quite cut it. But the fact of the matter is that fly.io is honed for an excellent developer experience (DX) for full stack applications with both realtime time and object storage requirements. + +There truly are only two steps involved. + +Step 1: [install flyctl](https://fly.io/docs/flyctl/install/) + +Step 2: run `fly launch --from https://github.com/fly-apps/node-dictaphone` or `fly launch --from https://github.com/fly-apps/rails-dictaphone` + +If you are new to fly, the second step will first take you to a place where you can register. Then it will provide a description of what you will be getting, and give you an opportunity to tweak the settings (suggestion: don't. They are fine for this demo and we will walk you through how to adjust them later). And then it will build and assemble and wire up your application. + +Take your time and play with it. Open your application in multiple browser windows. Send a link to a friend on another continent and watch your browser update in realtime. + +And then relax. We promised you it would be less than an hour. You are already up and running. In fact, if you are so inclined try bringing up this exact same application on another cloud provider. +We don't mind. In fact we encourage it. Just please don't count the time you spent there against the hour budget we asked you to allot to this activity. + +Once you are back and/or rested up, let's explore. You've seen the code. You're up and running. Now lets take inventory. +Feel free to review the following in any order, or chose to skip ahead: + * [Your application](../application/) + * [PostgreSQL](../postgresql/) + * [Tigris](../tigris/) + * [Redis](../redis/) + +Finally, as an added treat and as promised, let's add some AI functionality, in this case speech recognition using [Whisper](../whisper/). + +And when you are done, join us for a [recap](../recap) diff --git a/happy-path/index.html.markerb b/happy-path/index.html.markerb new file mode 100644 index 0000000000..fbd2a4d7d4 --- /dev/null +++ b/happy-path/index.html.markerb @@ -0,0 +1,33 @@ +--- +title: The Happy Path +layout: framework_docs +toc: false +--- + +You landed on this page because somebody recommended fly.io to you, +you are a bit curious, but you want to know more before you commit. + +You are aware that there is a [Speedrun](https://fly.io/speedrun) and +a [Quick Start](../getting-started/launch/), but perhaps they feel a bit +too _Ready! Fire! Aim!_ for you. You want to not only be up and running, +you want to feel confident that you are heading in the right direction. A +direction that can both scale and support your present and future needs. + +You are concerned about lock in. You want to be confident that you can +use services from other places and even eject entirely and move your entire +application elsewhere if things don't work out. + +But most of all, you want to explore in a time boxed way as you are +a busy person. If you don't get a good feeling within an hour, you are out +of here. If you do have a good feeling, then perhaps you'd consider +sticking around for even deeper dives into areas that interest you. + +If so, you have come to the right place. You should be up and +running within minutes, and have enough of the hour left over so +that you can spend some time understanding what you just did and +run a few commands and see what they do. + +And when you are done, you can delete everything and then launch the +application that you came here for. + +Let's get started... [Ready](./ready/) ... [Aim](./aim/) ... [Fire](./fire/)! diff --git a/happy-path/postgresql.html.markerb b/happy-path/postgresql.html.markerb new file mode 100644 index 0000000000..f7e9713d9d --- /dev/null +++ b/happy-path/postgresql.html.markerb @@ -0,0 +1,14 @@ +--- +title: PostgreSQL +layout: framework_docs_overview +order: 5 +--- + +Your application comes initially configured for a single [Fly Postgres](https://fly.io/docs/postgres/) machine. +That is great for development, but for production we need redundancy and scalability. With but a [few commands](https://fly.io/docs/postgres/advanced-guides/high-availability-and-global-replication/) we can create a HA cluster in my primary region and read only replicas elsewhere. + +If you are interested in a managed offering, [Supabase Postgres](https://fly.io/docs/reference/supabase/) is in public alpha. + +And there is no lock in here. We have a list of [recommended external providers](https://fly.io/docs/postgres/getting-started/what-you-should-know/#recommended-external-providers), but you are free to host your database literally anywhere. + +Before moving on, one last observation on the relational DB. While you want and need your application to be on the internet, you are much better off if your relational database is NOT directly exposed to the internet, but can only be accessed via your application. That’s the value of an [internal private network](https://fly.io/docs/networking/private-networking/). This too was configured automatically for you. \ No newline at end of file diff --git a/happy-path/ready.html.markerb b/happy-path/ready.html.markerb new file mode 100644 index 0000000000..290793e701 --- /dev/null +++ b/happy-path/ready.html.markerb @@ -0,0 +1,21 @@ +--- +title: Ready +layout: framework_docs_overview +order: 1 +--- + +You are not satisfied by a `hello world` or even a `hello world` with a database application. +You know that a real world application has at a minimum the following components: + +* A HTML form and a database. This database is typically a relational database. +* The ability to handle media files or documents, generally using S3. +* A multi-user and realtime component, where changes made by one person in one location are relected instantly in the browser of another person. + +While this doesn't seem like a tall ask, experience has shown that in order to get such an app running smoothly, you need a whole bunch of things; here are a few examples: anycast routing, load balancers, dns certificates, web sockets, an internal private network, a relational database, an object store, and an in-memory database. And the knowledge of how to connect them all together. + +Taken all together, this typically takes a **minimum** of an afternoon's worth of work, even by experts familiar with their target platform. With emphasis on the word _minimum_ as there always is a surprise, and often several. + +In the next few minutes we will have all this up and running, and can leisurely explore how the pieces fit together. We even will have enough time left over +to integrate in AI functionality making use of GPUs. + +With that understanding of requirements in place, lets proceed on.... [Aim](../aim/) diff --git a/happy-path/recap.html.markerb b/happy-path/recap.html.markerb new file mode 100644 index 0000000000..92ca778640 --- /dev/null +++ b/happy-path/recap.html.markerb @@ -0,0 +1,25 @@ +--- +title: Recap +layout: framework_docs_overview +order: 9 +--- + +We promised you that you could get through this in under an hour. How did we do? How much time did you have left over. + +You successfully deployed a full-stack application with both object storage and realtime requirements, and then went on to add AI functionality. + +Up front, we set some rather high goals: + +* You want to not only be up and running, + you want to feel confident that you are heading in the right direction. A + direction that can both scale and support your present and future needs. +* You want to be confident that you can + use services from other places and even eject entirely and move your entire + application elsewhere if things don't work out. + +Did we meet these goals? You've seen the code, and you've seen it work. You examined each component, and from there +saw links to where you can find out more information. + +Now a few links: + * [Support](https://fly.io/docs/about/support/) + * [Pricing](https://fly.io/docs/about/pricing/) \ No newline at end of file diff --git a/happy-path/redis.html.markerb b/happy-path/redis.html.markerb new file mode 100644 index 0000000000..c5f890beed --- /dev/null +++ b/happy-path/redis.html.markerb @@ -0,0 +1,12 @@ +--- +title: Upstash Redis +layout: framework_docs_overview +order: 7 +--- + +[Upstash Redis](https://fly.io/docs/reference/redis/) is used by this application for its [pubsub](https://redis.io/docs/latest/commands/?group=pubsub) +capabilities, but it can do [so much more](https://upstash.com/docs/redis/overall/rediscompatibility). + +In this application, updates are broadcast to all machines via Redis, and then each machine informs browser clients +of the update via [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). Client the request +updated information from the application using HTTP GET. \ No newline at end of file diff --git a/happy-path/tigris.html.markerb b/happy-path/tigris.html.markerb new file mode 100644 index 0000000000..f69a03573e --- /dev/null +++ b/happy-path/tigris.html.markerb @@ -0,0 +1,9 @@ +--- +title: Tigris +layout: framework_docs_overview +order: 6 +--- + +[Tigris](https://fly.io/docs/reference/tigris/) is truly a thing of beauty. It essentially requires no configuration, and seamlessly handles multi-regions. If you upload an audio file to a host in Virginia, you can access it from Amsterdam. Even better: subsequent accesses from regions other than the primary region are served locally. Unlike relational databases, there may be reasons why you want to make your object store available via the internet. In this demo, the object store starts out private, but you can make it [public](https://fly.io/docs/reference/tigris/#public-buckets) if you want. + +And if you happen to have an existing S3 object store, check out [shadow buckets](https://fly.io/docs/reference/tigris/#migrating-to-tigris-with-shadow-buckets) which enable you to incrementally migrate your data. \ No newline at end of file diff --git a/happy-path/whisper.html.markerb b/happy-path/whisper.html.markerb new file mode 100644 index 0000000000..4aad6f73c6 --- /dev/null +++ b/happy-path/whisper.html.markerb @@ -0,0 +1,25 @@ +--- +title: Whisper +layout: framework_docs_overview +order: 8 +--- + +Since you are now officially a fly.io expert, let's dive right in and run the following two commands in directory of your existing application: + +``` +fly launch --attach --from https://github.com/rubys/cog-whisper +fly deploy +``` + +Now try capturing a new audio clip. It will be transcribed automatically. + +Again, since you are now an expert, we can make this quick. You provisioned a new machine, this time with a [L40S](https://www.nvidia.com/en-us/data-center/l40s/) GPU. +It will stop when not in use. It will restart when a new request comes in. +It is only available on the private network using [FlyCast](https://fly.io/docs/networking/flycast/). +It runs [OpenAI Whisper](https://openai.com/index/whisper/) accessed via a [COG](https://github.com/replicate/cog) interface. + +This process involves taking audio clips from Tigris, passing them to Whisper, and updating Postgres with the results. +The Node code for this is about [two dozen lines of code](https://github.com/fly-apps/node-dictaphone/blob/1e84a4dece6888dfc68880d146b46511d47391b3/app.js#L102-L129), +and for Rails is about a [dozen](https://github.com/fly-apps/rails-dictaphone/blob/6bdf4f639640c9fb55530546dbbed682b65a7df9/app/jobs/whisper_transcribe_job.rb#L5-L16). + +And, as always, no lock in here. You can opt to replace this with a machine hosted by [Replicate](https://replicate.com/), or with a machine that you host this software elsewhere. From ac6b6ab91a80095a8fed6c6c357ded2f7faf6e61 Mon Sep 17 00:00:00 2001 From: Sam Ruby Date: Thu, 15 Aug 2024 03:35:47 -0400 Subject: [PATCH 2/3] mention caching as a potential use case for Redis --- happy-path/redis.html.markerb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/happy-path/redis.html.markerb b/happy-path/redis.html.markerb index c5f890beed..5c68cff45e 100644 --- a/happy-path/redis.html.markerb +++ b/happy-path/redis.html.markerb @@ -7,6 +7,10 @@ order: 7 [Upstash Redis](https://fly.io/docs/reference/redis/) is used by this application for its [pubsub](https://redis.io/docs/latest/commands/?group=pubsub) capabilities, but it can do [so much more](https://upstash.com/docs/redis/overall/rediscompatibility). +In particular, Redis is useful for caching: +[Node](https://redis.io/learn/develop/node/nodecrashcourse/caching), +[Rails](https://guides.rubyonrails.org/caching_with_rails.html#activesupport-cache-rediscachestore). + In this application, updates are broadcast to all machines via Redis, and then each machine informs browser clients of the update via [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). Client the request -updated information from the application using HTTP GET. \ No newline at end of file +updated information from the application using HTTP GET. From c9d182d7c97b3d22524ebb6d1b6444a2a8a9374b Mon Sep 17 00:00:00 2001 From: andie787 <4andie@gmail.com> Date: Mon, 19 Aug 2024 16:12:22 -0400 Subject: [PATCH 3/3] edits + some content re-org + new nav --- happy-path/aim.html.markerb | 63 +++++++++++++++++++---------- happy-path/application.html.markerb | 25 +++++------- happy-path/fire.html.markerb | 38 ++++++++++------- happy-path/index.html.markerb | 32 +++++---------- happy-path/postgresql.html.markerb | 12 +++--- happy-path/ready.html.markerb | 21 +++++----- happy-path/recap.html.markerb | 25 +++++------- happy-path/redis.html.markerb | 15 +++---- happy-path/tigris.html.markerb | 7 ++-- happy-path/whisper.html.markerb | 17 ++++---- partials/_demo_nav.html.erb | 33 +++++++++++++++ 11 files changed, 167 insertions(+), 121 deletions(-) create mode 100644 partials/_demo_nav.html.erb diff --git a/happy-path/aim.html.markerb b/happy-path/aim.html.markerb index c74d984172..80c72a0d05 100644 --- a/happy-path/aim.html.markerb +++ b/happy-path/aim.html.markerb @@ -1,34 +1,53 @@ --- -title: Aim -layout: framework_docs_overview +title: What is this deep dive demo? +layout: docs +nav: demo order: 2 --- -For this demo, we will start with [MDN's Web Dictaphone](https://github.com/mdn/dom-examples/tree/main/media/web-dictaphone#web-dictaphone). -You can play with a [live demo](https://mdn.github.io/dom-examples/media/web-dictaphone/). This is about as basic of an -HTML form as you can get, and it has the added bonus of providing the ability to generate as many media files as you want using only your voice. +To get the deep dive demo up and running on Fly.io, all you need is an empty directory and either Node or Ruby installed. But here are some more details about what the deep dive demo app actually is. -Your app undoubtely has many forms, and more complex forms, but once you can see the basic flow, the rest should be easy. +The important thing to note is that this is all very straightforward stuff using industry standard components that you can run on your laptop, a VPS, AWS EC2, Google Compute Engine, or Azure. -That demo as it currently stands is client side only, so to deploy it all you need is a web server that can deploy static assets (HTML, CSS, JS, images), -like NGINX, Apache HTTPd, or Caddy. In order to store the data in databases, we are going to need a server that can handle HTTP GET, POST, PUT, and DELETE requests. +The deep dive demo is based on [MDN's Web Dictaphone](https://github.com/mdn/dom-examples/tree/main/media/web-dictaphone+external). +You can play with a [live demo hosted on GitHub](https://mdn.github.io/dom-examples/media/web-dictaphone/+external). The Web Dictaphone app is about as basic of an HTML form as you can get, and it has the added bonus of providing the ability to generate as many media files as you want using only your voice. -This demo application will come in two flavors. For Node.js, we will select [Express.JS](https://expressjs.com/), and for Rails we will use [Puma](https://github.com/puma/puma). +Your own app might have many forms, and more complex forms, but the dictaphone app demonstrates the the basic flow. -* The names of the clips will go into a [PostgreSQL](https://www.postgresql.org/) relational database. -* The audio files themselves will be placed into a [Tigris bucket](https://www.tigrisdata.com/). -* For Node.js, the bulk of this code is in [app.js](https://github.com/fly-apps/node-dictaphone/blob/main/app.js). For Rails, -[app/controller/clipController.rb](https://github.com/fly-apps/rails-dictaphone/blob/main/app/controllers/clips_controller.rb). +The basic Web Dictaphone is client side only, requiring a web server that can deploy static assets (HTML, CSS, JS, images), like NGINX, Apache HTTPd, or Caddy. Storing the data in databases requires a server that can handle HTTP GET, POST, PUT, and DELETE requests. -To satisfy the realtime requirement, we will need [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) -and [Upstash for Redis](https://fly.io/docs/reference/redis/). The Node.js implementation is in [pubsub.js](https://github.com/fly-apps/node-dictaphone/blob/main/pubsub.js). -For Rails, the heavy lifting is done by [ActionCable](https://guides.rubyonrails.org/action_cable_overview.html), so all that is needed is -one line in [app/models/clip.rb](https://github.com/fly-apps/rails-dictaphone/blob/6bdf4f639640c9fb55530546dbbed682b65a7df9/app/models/clip.rb#L2) -and one line in [app/views/layouts/application.html.erb](https://github.com/fly-apps/rails-dictaphone/blob/6bdf4f639640c9fb55530546dbbed682b65a7df9/app/views/layouts/application.html.erb#L9). +Our deep dive demo comes in two flavors: -The important thing to note is that this is all very straightforward stuff using industry standard components that you can run on your laptop, a VPS, AWS EC2, Google Compute Engine, or Azure. +- Node.js +- Rails + +The demo uses the following database and storage: + +* A [PostgreSQL](https://www.postgresql.org/+external) relational database to store the names of the audio clips +* A [Tigris bucket](https://www.tigrisdata.com/+external) to store the the audio files + +To satisfy the realtime requirement, the demo uses: + +- [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API+external) +- [Upstash for Redis](https://fly.io/docs/reference/redis/) + +## Node.js + +The Node.js flavor of the deep dive demo uses an [Express.JS](https://expressjs.com/+external) server. + +If you're looking for specific code: + +* The bulk of the app code is in [app.js](https://github.com/fly-apps/node-dictaphone/blob/main/app.js) +* The realtime implementation code is in [pubsub.js](https://github.com/fly-apps/node-dictaphone/blob/main/pubsub.js) + +## Rails + +The Rails flavor of the deep dive demo uses a [Puma](https://github.com/puma/puma+external) server. + +If you're looking for specific code: -If you want to see this up and running on fly.io (and certainly you do or why else would you be here?), all you need -is an empty directory and either Node or Ruby installed. +* The bulk of the app code is in [app/controller/clipController.rb](https://github.com/fly-apps/rails-dictaphone/blob/main/app/controllers/clips_controller.rb) +* The realtime implementation code is primarily in [ActionCable](https://guides.rubyonrails.org/action_cable_overview.html), so all that is needed is one line in [app/models/clip.rb](https://github.com/fly-apps/rails-dictaphone/blob/6bdf4f639640c9fb55530546dbbed682b65a7df9/app/models/clip.rb#L2) +and one line in [app/views/layouts/application.html.erb](https://github.com/fly-apps/rails-dictaphone/blob/6bdf4f639640c9fb55530546dbbed682b65a7df9/app/views/layouts/application.html.erb#L9) -Now that we know what we are intending to accomplish, let's proceed to the exciting step: [Fire!](../fire/) +**Next:** Now that you know what you're about to deploy, the next step is running [`fly launch`](../fire/). diff --git a/happy-path/application.html.markerb b/happy-path/application.html.markerb index b52ee41a4b..e25a3f976e 100644 --- a/happy-path/application.html.markerb +++ b/happy-path/application.html.markerb @@ -1,23 +1,20 @@ --- -title: Your Application -layout: framework_docs_overview +title: Your Fly App +layout: docs +nav: demo order: 4 --- -Your application is running by default on two [Machines](https://fly.io/docs/machines/). +Your demo app is running by default on two [Machines](https://fly.io/docs/machines/). -Don't worry about cost. Both machines stop when not in use, and [autostart](https://fly.io/docs/launch/autostop-autostart/) when a new request comes in. -This is entirely configurable. You can chose to [suspend](https://community.fly.io/t/new-feature-in-preview-suspend-resume-for-machines/20672) instead of stop, -configure a [minimum number](https://fly.io/docs/reference/configuration/#the-http_service-section) of machines to leave running, or even decide never to -stop at all. +Both Machines stop when not in use, and [autostart](https://fly.io/docs/launch/autostop-autostart/) when a new request comes in. +This is entirely configurable. You can chose to [suspend](https://community.fly.io/t/new-feature-in-preview-suspend-resume-for-machines/20672) instead of stop, configure a [minimum number](https://fly.io/docs/reference/configuration/#the-http_service-section) of Machines to leave running, or even decide never to stop Machines at all. -Familiarize yourself with [fly.toml](https://fly.io/docs/reference/configuration/). Make a change there -- or in fact to any part of your application -- and run `fly deploy`. +Familiarize yourself with the [fly.toml](https://fly.io/docs/reference/configuration/) config file. Make a change there -- or in fact to any part of your application -- and run `fly deploy`. -The purpose of two machines is twofold: redundancy and scalability. If the machine hosting one goes down, the other can continue on. If both are available, in times of high use both can be started to handle requests. -You can [vertically scale](https://fly.io/docs/launch/scale-machine/) the CPU and RAM on each machine. +The purpose of two Machines is twofold: redundancy and scalability. If the Machine hosting one goes down, the other can continue on. If both are available, in times of high use both can be started to handle requests. +You can [vertically scale](https://fly.io/docs/launch/scale-machine/) the CPU and RAM on each Machine. -You can also [horizontally scale](https://fly.io/docs/launch/scale-count/) to more machines. Be sure to scroll down on that page far enough to see how to scale to -multiple [regions](https://fly.io/docs/reference/regions/). If you have a co-worker on another continent, create a machine there. +You can also [horizontally scale](https://fly.io/docs/launch/scale-count/) to more Machines. Be sure to scroll down on that page far enough to see how to scale to multiple [regions](https://fly.io/docs/reference/regions/). If you have a co-worker on another continent, create a Machine there. -And all this is made possible by [Anycast](https://fly.io/docs/networking/services/), a [load balancing proxy](https://fly.io/docs/reference/fly-proxy/), and [DNS certificates](https://fly.io/docs/networking/custom-domain/). -Be sure to read the last link if you are interested in custom domains. +All this is made possible by [Anycast](https://fly.io/docs/networking/services/), a [load balancing proxy](https://fly.io/docs/reference/fly-proxy/), and [DNS certificates](https://fly.io/docs/networking/custom-domain/). Be sure to read that last link if you're interested in custom domains. diff --git a/happy-path/fire.html.markerb b/happy-path/fire.html.markerb index 9775fd70bc..cec45b9e9c 100644 --- a/happy-path/fire.html.markerb +++ b/happy-path/fire.html.markerb @@ -1,32 +1,40 @@ --- -title: Fire -layout: framework_docs_overview +title: Launch the demo +layout: docs +nav: demo order: 3 --- -This is the point where the rubber meets the road, so this is where you would expect to see where the marketing hype promised by [Speedrun](https://fly.io/speedrun) and -the [Quick Start](../getting-started/launch/) don't quite cut it. But the fact of the matter is that fly.io is honed for an excellent developer experience (DX) for full stack applications with both realtime time and object storage requirements. +This is the point where you might expect to see that the marketing hype promised by [Speedrun](https://fly.io/speedrun) doesn't quite cut it. But the fact is that Fly.io is built for an excellent developer experience (DX) for full stack applications with both realtime time and object storage requirements. -There truly are only two steps involved. +There are only two steps. -Step 1: [install flyctl](https://fly.io/docs/flyctl/install/) +**Step 1:** [Install flyctl](https://fly.io/docs/flyctl/install/). -Step 2: run `fly launch --from https://github.com/fly-apps/node-dictaphone` or `fly launch --from https://github.com/fly-apps/rails-dictaphone` +**Step 2:** Run: +```cmd +fly launch --from https://github.com/fly-apps/node-dictaphone +``` +-or- +```cmd +fly launch --from https://github.com/fly-apps/rails-dictaphone +``` -If you are new to fly, the second step will first take you to a place where you can register. Then it will provide a description of what you will be getting, and give you an opportunity to tweak the settings (suggestion: don't. They are fine for this demo and we will walk you through how to adjust them later). And then it will build and assemble and wire up your application. +If you are new to Fly.io, the second step will take you to a page where you can register before continuing. -Take your time and play with it. Open your application in multiple browser windows. Send a link to a friend on another continent and watch your browser update in realtime. +The `fly launch` output describes what you'll be getting for the app, and gives you an opportunity to tweak the settings (suggestion: Don't. The defaults are fine for this demo and we'll walk you through how to adjust them later). And then it will build and assemble and wire up your app. -And then relax. We promised you it would be less than an hour. You are already up and running. In fact, if you are so inclined try bringing up this exact same application on another cloud provider. -We don't mind. In fact we encourage it. Just please don't count the time you spent there against the hour budget we asked you to allot to this activity. +Take your time and play with it. Open the application in multiple browser windows. Send a link to a friend on another continent and watch your browser update in realtime. + +And then relax. We promised you it would be less than an hour. You're already up and running. If you are so inclined, try bringing up this exact same application on another cloud provider. We don't mind. In fact, we encourage it. Just please don't count the time you spent there against the hour budget we asked you to allot to this activity. + +Once you're back and/or rested up, explore app and add-on components. Feel free to review the following in any order, or chose to skip ahead: -Once you are back and/or rested up, let's explore. You've seen the code. You're up and running. Now lets take inventory. -Feel free to review the following in any order, or chose to skip ahead: * [Your application](../application/) * [PostgreSQL](../postgresql/) * [Tigris](../tigris/) * [Redis](../redis/) -Finally, as an added treat and as promised, let's add some AI functionality, in this case speech recognition using [Whisper](../whisper/). +Finally, as an added treat, you can add some AI functionality, in this case speech recognition using [Whisper](../whisper/). -And when you are done, join us for a [recap](../recap) +When you're all done, visit the [recap](../recap). diff --git a/happy-path/index.html.markerb b/happy-path/index.html.markerb index fbd2a4d7d4..d2d1314911 100644 --- a/happy-path/index.html.markerb +++ b/happy-path/index.html.markerb @@ -1,33 +1,21 @@ --- -title: The Happy Path -layout: framework_docs +title: Deep dive demo +layout: docs +nav: demo toc: false --- -You landed on this page because somebody recommended fly.io to you, -you are a bit curious, but you want to know more before you commit. +You probably landed on this page because somebody recommended Fly.io to you. You're curious, and you want to know more before you commit. -You are aware that there is a [Speedrun](https://fly.io/speedrun) and -a [Quick Start](../getting-started/launch/), but perhaps they feel a bit -too _Ready! Fire! Aim!_ for you. You want to not only be up and running, -you want to feel confident that you are heading in the right direction. A -direction that can both scale and support your present and future needs. +If you came from our [Speedrun](https://fly.io/speedrun) or [Getting started](https://fly.io/docs/getting-started/) pages, maybe you want to not only be up and running fast, you want to feel confident that you're making a good decision; choosing a platform that can both support you now, and scale with you later on as you grow. -You are concerned about lock in. You want to be confident that you can +Maybe you're concerned about lock in. You want to know that you can use services from other places and even eject entirely and move your entire application elsewhere if things don't work out. -But most of all, you want to explore in a time boxed way as you are -a busy person. If you don't get a good feeling within an hour, you are out -of here. If you do have a good feeling, then perhaps you'd consider -sticking around for even deeper dives into areas that interest you. +If you want to explore more deeply but in a time-boxed way, then you're in the right place. You should be up and running within minutes, and have enough of the hour left over to spend some time understanding what you just did and run a few commands and see what they do. -If so, you have come to the right place. You should be up and -running within minutes, and have enough of the hour left over so -that you can spend some time understanding what you just did and -run a few commands and see what they do. +If you don't get a good feeling within an hour, you're out of here. If you do get a good feeling, then consider +sticking around to experiment and learn more about features that interest you. And when you're done, you can delete everything and launch the application that you brought here to launch. -And when you are done, you can delete everything and then launch the -application that you came here for. - -Let's get started... [Ready](./ready/) ... [Aim](./aim/) ... [Fire](./fire/)! +**Next:** [Beyond `hello fly`](/docs/happy-path/ready/) diff --git a/happy-path/postgresql.html.markerb b/happy-path/postgresql.html.markerb index f7e9713d9d..a4917c571a 100644 --- a/happy-path/postgresql.html.markerb +++ b/happy-path/postgresql.html.markerb @@ -1,14 +1,14 @@ --- title: PostgreSQL -layout: framework_docs_overview +layout: docs order: 5 +nav: demo --- -Your application comes initially configured for a single [Fly Postgres](https://fly.io/docs/postgres/) machine. -That is great for development, but for production we need redundancy and scalability. With but a [few commands](https://fly.io/docs/postgres/advanced-guides/high-availability-and-global-replication/) we can create a HA cluster in my primary region and read only replicas elsewhere. +Fly Postgres is deployed as a separate app, and that app comes initially configured with a single [Fly Postgres](https://fly.io/docs/postgres/) Machine. That's fine for development, but for production you need redundancy and scalability. With a [few commands](https://fly.io/docs/postgres/advanced-guides/high-availability-and-global-replication/) you can create an HA cluster in your primary region and read-only replicas elsewhere. -If you are interested in a managed offering, [Supabase Postgres](https://fly.io/docs/reference/supabase/) is in public alpha. +If you're interested in a managed offering, [Supabase Postgres](https://fly.io/docs/reference/supabase/) is in public alpha. -And there is no lock in here. We have a list of [recommended external providers](https://fly.io/docs/postgres/getting-started/what-you-should-know/#recommended-external-providers), but you are free to host your database literally anywhere. +And there is no lock in here. We have a list of [recommended external providers](https://fly.io/docs/postgres/getting-started/what-you-should-know/#recommended-external-providers), but you're free to host your database literally anywhere. -Before moving on, one last observation on the relational DB. While you want and need your application to be on the internet, you are much better off if your relational database is NOT directly exposed to the internet, but can only be accessed via your application. That’s the value of an [internal private network](https://fly.io/docs/networking/private-networking/). This too was configured automatically for you. \ No newline at end of file +Before moving on, one last observation on the relational database. While you want and need your application to be on the internet, you are much better off if your relational database is NOT directly exposed to the internet, but can only be accessed via your application. That’s the value of an [internal private network](https://fly.io/docs/networking/private-networking/). The private connection from the demo app to the Postgres app was configured automatically for you. diff --git a/happy-path/ready.html.markerb b/happy-path/ready.html.markerb index 290793e701..78d7036aea 100644 --- a/happy-path/ready.html.markerb +++ b/happy-path/ready.html.markerb @@ -1,21 +1,20 @@ --- -title: Ready -layout: framework_docs_overview +title: Beyond "hello fly" +layout: docs +nav: demo order: 1 --- -You are not satisfied by a `hello world` or even a `hello world` with a database application. -You know that a real world application has at a minimum the following components: +If you're not satisfied by a `hello world`, or even a `hello world` with a database application, it's because you know that a real-world application has at a minimum the following components: -* A HTML form and a database. This database is typically a relational database. +* An HTML form and a database; typically a relational database. * The ability to handle media files or documents, generally using S3. -* A multi-user and realtime component, where changes made by one person in one location are relected instantly in the browser of another person. +* A multi-user and realtime component, where changes made by one person in one location are reflected instantly in the browser of another person. -While this doesn't seem like a tall ask, experience has shown that in order to get such an app running smoothly, you need a whole bunch of things; here are a few examples: anycast routing, load balancers, dns certificates, web sockets, an internal private network, a relational database, an object store, and an in-memory database. And the knowledge of how to connect them all together. +While this doesn't seem like a big ask, experience shows that to get a fully-functional app running smoothly, you need a whole bunch of things; here are a few examples: Anycast routing, load balancers, DNS certificates, WebSockets, an internal private network, a relational database, an object store, and an in-memory database. And the knowledge of how to connect them all together. -Taken all together, this typically takes a **minimum** of an afternoon's worth of work, even by experts familiar with their target platform. With emphasis on the word _minimum_ as there always is a surprise, and often several. +Set up for a complete app typically takes a _minimum_ of an afternoon's worth of work, even by experts familiar with their target platform. With emphasis on the word _minimum_ as there is almost always a surprise, and often several. -In the next few minutes we will have all this up and running, and can leisurely explore how the pieces fit together. We even will have enough time left over -to integrate in AI functionality making use of GPUs. +In the next few minutes you'll have all this up and running, and can leisurely explore how the pieces fit together. You'll even have enough time left over to integrate in AI functionality making use of GPUs. -With that understanding of requirements in place, lets proceed on.... [Aim](../aim/) +**Next:** [What is this deep dive demo anyway?](../aim/) diff --git a/happy-path/recap.html.markerb b/happy-path/recap.html.markerb index 92ca778640..1f0cb83cf4 100644 --- a/happy-path/recap.html.markerb +++ b/happy-path/recap.html.markerb @@ -1,25 +1,22 @@ --- title: Recap -layout: framework_docs_overview +layout: docs +nav: demo order: 9 --- -We promised you that you could get through this in under an hour. How did we do? How much time did you have left over. +We promised you that you could get through this in under an hour. +You successfully deployed a full-stack app with both object storage and realtime requirements, and then went on to add AI functionality. -You successfully deployed a full-stack application with both object storage and realtime requirements, and then went on to add AI functionality. +Up front, we set some goals: -Up front, we set some rather high goals: - -* You want to not only be up and running, - you want to feel confident that you are heading in the right direction. A - direction that can both scale and support your present and future needs. -* You want to be confident that you can - use services from other places and even eject entirely and move your entire +* You want to not only be up and running quickly, you want to feel confident that you're making a good decision; choosing a platform that can both support you now, and scale with you later on as you grow. +* You want to know that you can still use services from other places and even eject entirely and move your entire application elsewhere if things don't work out. -Did we meet these goals? You've seen the code, and you've seen it work. You examined each component, and from there -saw links to where you can find out more information. +How did we do? + +More info about Fly.io: -Now a few links: * [Support](https://fly.io/docs/about/support/) - * [Pricing](https://fly.io/docs/about/pricing/) \ No newline at end of file + * [Pricing](https://fly.io/docs/about/pricing/) diff --git a/happy-path/redis.html.markerb b/happy-path/redis.html.markerb index 5c68cff45e..ff8f23559d 100644 --- a/happy-path/redis.html.markerb +++ b/happy-path/redis.html.markerb @@ -1,16 +1,17 @@ --- title: Upstash Redis -layout: framework_docs_overview +layout: docs +nav: demo order: 7 --- -[Upstash Redis](https://fly.io/docs/reference/redis/) is used by this application for its [pubsub](https://redis.io/docs/latest/commands/?group=pubsub) -capabilities, but it can do [so much more](https://upstash.com/docs/redis/overall/rediscompatibility). +[Upstash Redis](https://fly.io/docs/reference/redis/) is used by the deep dive demo app for its [pubsub](https://redis.io/docs/latest/commands/?group=pubsub) capabilities, but it can do [so much more](https://upstash.com/docs/redis/overall/rediscompatibility). In particular, Redis is useful for caching: -[Node](https://redis.io/learn/develop/node/nodecrashcourse/caching), -[Rails](https://guides.rubyonrails.org/caching_with_rails.html#activesupport-cache-rediscachestore). -In this application, updates are broadcast to all machines via Redis, and then each machine informs browser clients -of the update via [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). Client the request +- [Node and Redis](https://redis.io/learn/develop/node/nodecrashcourse/caching+external) +- [Rails and Redis](https://guides.rubyonrails.org/caching_with_rails.html#activesupport-cache-rediscachestore+external) + +In the deep dive demo app, updates are broadcast to all Machines via Redis, and then each Machine informs browser clients +of the update via [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API+external). The client requests updated information from the application using HTTP GET. diff --git a/happy-path/tigris.html.markerb b/happy-path/tigris.html.markerb index f69a03573e..9f8f06416a 100644 --- a/happy-path/tigris.html.markerb +++ b/happy-path/tigris.html.markerb @@ -1,9 +1,10 @@ --- title: Tigris -layout: framework_docs_overview +layout: docs +nav: demo order: 6 --- -[Tigris](https://fly.io/docs/reference/tigris/) is truly a thing of beauty. It essentially requires no configuration, and seamlessly handles multi-regions. If you upload an audio file to a host in Virginia, you can access it from Amsterdam. Even better: subsequent accesses from regions other than the primary region are served locally. Unlike relational databases, there may be reasons why you want to make your object store available via the internet. In this demo, the object store starts out private, but you can make it [public](https://fly.io/docs/reference/tigris/#public-buckets) if you want. +[Tigris](https://fly.io/docs/reference/tigris/) is a globally distributed object storag service. It essentially requires no configuration, and seamlessly handles multi-regions. If you upload an audio file to a host in Virginia, you can access it from Amsterdam. Even better: subsequent accesses from regions other than the primary region are served locally. Unlike relational databases, there may be reasons why you want to make your object store available via the internet. In this demo, the object store starts out private, but you can make it [public](https://fly.io/docs/reference/tigris/#public-buckets) if you want. -And if you happen to have an existing S3 object store, check out [shadow buckets](https://fly.io/docs/reference/tigris/#migrating-to-tigris-with-shadow-buckets) which enable you to incrementally migrate your data. \ No newline at end of file +And if you happen to have an existing S3 object store, check out [shadow buckets](https://fly.io/docs/reference/tigris/#migrating-to-tigris-with-shadow-buckets) which enable you to incrementally migrate your data. diff --git a/happy-path/whisper.html.markerb b/happy-path/whisper.html.markerb index 4aad6f73c6..6aad5114ca 100644 --- a/happy-path/whisper.html.markerb +++ b/happy-path/whisper.html.markerb @@ -1,25 +1,28 @@ --- title: Whisper -layout: framework_docs_overview +layout: docs +nav: demo order: 8 --- -Since you are now officially a fly.io expert, let's dive right in and run the following two commands in directory of your existing application: +Since you are now officially a Fly.io expert, let's dive right in and run the following two commands in the project directory of your deep dive demo app: ``` fly launch --attach --from https://github.com/rubys/cog-whisper fly deploy ``` -Now try capturing a new audio clip. It will be transcribed automatically. +Next try capturing a new audio clip. It will be transcribed automatically. -Again, since you are now an expert, we can make this quick. You provisioned a new machine, this time with a [L40S](https://www.nvidia.com/en-us/data-center/l40s/) GPU. -It will stop when not in use. It will restart when a new request comes in. -It is only available on the private network using [FlyCast](https://fly.io/docs/networking/flycast/). +## What happened + +You provisioned a new Machine, this time with an [L40S](https://www.nvidia.com/en-us/data-center/l40s/) GPU. +It will stop when not in use. It will restart when a new request comes in. +It is only available on the private network using [Flycast](https://fly.io/docs/networking/flycast/). It runs [OpenAI Whisper](https://openai.com/index/whisper/) accessed via a [COG](https://github.com/replicate/cog) interface. This process involves taking audio clips from Tigris, passing them to Whisper, and updating Postgres with the results. The Node code for this is about [two dozen lines of code](https://github.com/fly-apps/node-dictaphone/blob/1e84a4dece6888dfc68880d146b46511d47391b3/app.js#L102-L129), and for Rails is about a [dozen](https://github.com/fly-apps/rails-dictaphone/blob/6bdf4f639640c9fb55530546dbbed682b65a7df9/app/jobs/whisper_transcribe_job.rb#L5-L16). -And, as always, no lock in here. You can opt to replace this with a machine hosted by [Replicate](https://replicate.com/), or with a machine that you host this software elsewhere. +And, as always, no lock in here. You can opt to replace this with a machine hosted by [Replicate](https://replicate.com/) or elsewhere. diff --git a/partials/_demo_nav.html.erb b/partials/_demo_nav.html.erb new file mode 100644 index 0000000000..c61f33993b --- /dev/null +++ b/partials/_demo_nav.html.erb @@ -0,0 +1,33 @@ +<%= partial "/docs/partials/back_to_docs" unless current_page?('/docs') %> + +<% + @nav = [ + { + title: "Deep Dive Demo", + path: "/docs/happy-path/", + accordion: true, + open: true, + links: [ + { text: "Beyond \"hello fly\"", path: "/docs/happy-path/ready/" }, + { text: "What is this deep dive demo?", path: "/docs/happy-path/aim/" }, + { text: "Launch the demo", path: "/docs/happy-path/fire/" } + ] + }, + { + title: "What You Get", + open: true, + links: [ + { text: "The Fly App", path: "/docs/happy-path/application/" }, + { text: "PostgreSQL", path: "/docs/happy-path/postgresql/" }, + { text: "Tigris Object Storage", path: "/docs/happy-path/tigris/" }, + { text: "Upstash Redis", path: "/docs/happy-path/redis/" }, + { text: "Whisper", path: "/docs/happy-path/whisper/" } + ] + }, + { + title: "Recap", + path: "/docs/happy-path/recap", + } + ] +%> +<%= partial "/docs/partials/accordion_nav", locals: { nav: @nav } %>