mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-12-18 22:21:32 +08:00
Remove pitfalls from deployment notebook
This commit is contained in:
parent
47fe94f560
commit
22ace2ca4f
2 changed files with 51 additions and 41 deletions
|
|
@ -10,6 +10,7 @@
|
||||||
.ri-livebook-shortcuts,
|
.ri-livebook-shortcuts,
|
||||||
.ri-livebook-secrets,
|
.ri-livebook-secrets,
|
||||||
.ri-livebook-deploy,
|
.ri-livebook-deploy,
|
||||||
|
.ri-livebook-terminal,
|
||||||
.ri-livebook-save {
|
.ri-livebook-save {
|
||||||
@apply text-xl align-middle;
|
@apply text-xl align-middle;
|
||||||
}
|
}
|
||||||
|
|
@ -34,6 +35,10 @@
|
||||||
content: "\f096";
|
content: "\f096";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ri-livebook-terminal:before {
|
||||||
|
content: "\f1f8";
|
||||||
|
}
|
||||||
|
|
||||||
.ri-livebook-save:before {
|
.ri-livebook-save:before {
|
||||||
content: "\f0b3";
|
content: "\f0b3";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,34 +56,33 @@ re-execute the cell above. For each click, there is a new message in
|
||||||
our inbox. There are several ways we can consume this message.
|
our inbox. There are several ways we can consume this message.
|
||||||
Let's see a different one in the next example.
|
Let's see a different one in the next example.
|
||||||
|
|
||||||
<!-- livebook:{"branch_parent_index":0} -->
|
|
||||||
|
|
||||||
## Enumerating controls
|
## Enumerating controls
|
||||||
|
|
||||||
All Kino controls are enumerable. This means we can treat them
|
All Kino controls are enumerable. This means we can treat them
|
||||||
as a collection, an infinite collection in this case, and consume
|
as a collection, an infinite stream of events in this case.
|
||||||
their events. Let's define another button:
|
Let's define another button:
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
click_me_again = Kino.Control.button("Click me again!")
|
click_me_again = Kino.Control.button("Click me again!")
|
||||||
```
|
```
|
||||||
|
|
||||||
And now let's consume it:
|
And now let's consume those events. Because the stream is
|
||||||
|
infinite, we will consume them inside a separate process,
|
||||||
|
in order to not block our notebook:
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
|
spawn(fn ->
|
||||||
for event <- click_me_again do
|
for event <- click_me_again do
|
||||||
IO.inspect(event)
|
IO.inspect(event)
|
||||||
end
|
end
|
||||||
|
end)
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, as you submit the button, you should see a new event
|
Now, as you submit the button, you should see a new event
|
||||||
printed. However, there is a downside: we are now stuck
|
printed. It happens this pattern of consuming events without
|
||||||
inside this infinite loop of events. Luckily, we started
|
blocking the notebook is so common that `Kino` even has a
|
||||||
this particular section as a branched section, which means
|
convenience functions for it, such as `Kino.animate/2` and
|
||||||
the main execution flow will not be interrupted. But it
|
`Kino.listen/2`. Let's keep on learning.
|
||||||
is something you should keep in mind in the future. You
|
|
||||||
can also stop it by pressing the "Stop" button above the
|
|
||||||
Code cell.
|
|
||||||
|
|
||||||
## Kino.Frame and animations
|
## Kino.Frame and animations
|
||||||
|
|
||||||
|
|
@ -175,10 +174,10 @@ inputs = [
|
||||||
form = Kino.Control.form(inputs, submit: "Send", reset_on_submit: [:message])
|
form = Kino.Control.form(inputs, submit: "Send", reset_on_submit: [:message])
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, every time the form is submitted, we want to append
|
Now we want to append the message to a frame every time the
|
||||||
the message to a frame. We have learned about `Kino.animate/3`,
|
form is submitted. We have learned about `Kino.animate/3`,
|
||||||
that receives control events, but unfortunately it only updates
|
that receives control events, but unfortunately it only updates
|
||||||
frames in place, while we want to always append content.
|
frames in place while we want to always append content.
|
||||||
We could accumulate the content ourselves and always re-render
|
We could accumulate the content ourselves and always re-render
|
||||||
it all on the frame, but that sounds a bit wasteful.
|
it all on the frame, but that sounds a bit wasteful.
|
||||||
|
|
||||||
|
|
@ -203,16 +202,27 @@ Execute the cell above and your chat app should be
|
||||||
fully operational. Scroll up, submit messages via the
|
fully operational. Scroll up, submit messages via the
|
||||||
form, and see them appear in the frame.
|
form, and see them appear in the frame.
|
||||||
|
|
||||||
Implementation-wise, our `listen` above receives the
|
Implementation-wise, the call to `listen` receives the
|
||||||
form events, which includes the value of each input.
|
form events, which includes the value of each input.
|
||||||
If a name and message have been given, we append it
|
If a name and message have been given, we append it
|
||||||
to the frame. If one of them is missing, we append an
|
to the frame.
|
||||||
error message to the frame with the `to: origin` option.
|
|
||||||
This means that particular message will be sent only to
|
The `append` function also accepts two options worth
|
||||||
the user who submitted the form, instead of everyone.
|
discussing. The first one, used in the example above,
|
||||||
|
is the `to: origin` option. This means the particular
|
||||||
|
message will be sent only to the user who submitted
|
||||||
|
the form, instead of everyone.
|
||||||
|
|
||||||
|
Another option frequently used is `:temporary`. All
|
||||||
|
messages are stored in the frame by default. This means
|
||||||
|
that, if you reload the page, or join late, you can see
|
||||||
|
all history. If you set `:temporary` to true, that will
|
||||||
|
no longer be the case. Note all messages sent with the
|
||||||
|
`:to` option are temporary.
|
||||||
|
|
||||||
You can also open up this notebook on different tabs
|
You can also open up this notebook on different tabs
|
||||||
and emulate how different users can chat with each other.
|
and emulate how different users can chat with each other.
|
||||||
|
Give it a try!
|
||||||
|
|
||||||
## Deploying
|
## Deploying
|
||||||
|
|
||||||
|
|
@ -224,26 +234,21 @@ Now, define a slug for your deployment, such as "chat-app",
|
||||||
set a password (or disable password protection), and click
|
set a password (or disable password protection), and click
|
||||||
"Deploy".
|
"Deploy".
|
||||||
|
|
||||||
Once you do so, you will see that... the deployed application
|
Now you can click the URL and interact with the chat app,
|
||||||
will be in a "Booting" state forever? Well, clearly something
|
as you did inside the notebook. There are a couple things to
|
||||||
has gone wrong.
|
keep in mind:
|
||||||
|
|
||||||
To understand what went wrong, we need to talk about how
|
* Deployed applications only show `Kino` outputs. Sections,
|
||||||
the Deploy feature works. When you deploy a notebook,
|
Markdown, non-Kino results, are all discarded.
|
||||||
Livebook will execute all of the code cells in the notebook.
|
|
||||||
Your application will effectively be all frames, controls,
|
|
||||||
etc. that you rendered on the page. Once all cells _successfully
|
|
||||||
evaluate_, the application finishes booting.
|
|
||||||
|
|
||||||
However, if you remember the "Enumerating controls" section,
|
* To deploy a notebook, Livebook will execute all of the code
|
||||||
we did create an infinite loop there! And because that cell
|
cells in the notebook from beginning to end. If your notebook
|
||||||
never terminates, the booting process never completes.
|
cannot fully execute all of its cells, then its deployment
|
||||||
|
will be in a "Booting" stage forever. You can click the
|
||||||
|
<i class="ri-livebook-terminal"></i> icon on the deployment
|
||||||
|
to join its session and debug it.
|
||||||
|
|
||||||
The solution is easy, delete the whole "Enumerating controls"
|
That's it. Feel free to adjust the deployed application, by
|
||||||
section (or just that code cell), and try again. Now booting should
|
removing unused outputs or by adding new features.
|
||||||
finish rather quickly and you will be able to interact with
|
|
||||||
your newly deployed app. Feel free to further improve it,
|
|
||||||
by removing frames from previous sections that do not belong
|
|
||||||
to the chat app or by adding new features.
|
|
||||||
|
|
||||||
Congratulations on shipping!
|
Congratulations on shipping!
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue