Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WJ-1187] Automatic reload on configuration change #1626

Merged
merged 34 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1eed7cc
Add local / deploy features, add notify dependency.
emmiegit Sep 28, 2023
0154c56
Add features to Dockerfiles.
emmiegit Sep 29, 2023
a51ee58
Add compile features to README.
emmiegit Sep 28, 2023
9f3824b
Update structure line in README.
emmiegit Sep 28, 2023
a703215
Update build commands for new features.
emmiegit Sep 28, 2023
548272d
Begin autorestart module.
emmiegit Sep 28, 2023
6204c71
Fix typo.
emmiegit Sep 28, 2023
4fe673c
Store config TOML file in Config struct.
emmiegit Sep 28, 2023
07fc514
Add /config/path route.
emmiegit Sep 28, 2023
4b49ba8
Start setup_autorestart().
emmiegit Sep 28, 2023
ea31701
Implement filesystem event handler.
emmiegit Sep 28, 2023
4fd106c
Implement restart_self().
emmiegit Sep 28, 2023
0bdf5ef
Add --watch-config argument for new feature.
emmiegit Sep 29, 2023
4db10c3
Add execution section, and explain new argument.
emmiegit Sep 29, 2023
9ac0400
Add runtime error if notify feature is missing.
emmiegit Sep 29, 2023
fef89c4
Add --watch-files to local api invocation.
emmiegit Sep 29, 2023
e607e4e
Add comment explaining locale directory.
emmiegit Sep 29, 2023
ee94845
Change -w to be set-true.
emmiegit Sep 29, 2023
cf988b7
Rename restart.rs -> watch.rs
emmiegit Sep 29, 2023
6dffda8
Add log messages on watch start.
emmiegit Sep 29, 2023
83fd543
Fix discarded watcher issue.
emmiegit Sep 29, 2023
e680caf
Use watched_paths to store paths, canonicalize.
emmiegit Sep 29, 2023
2b39b33
Fix exec() to not duplicate executable.
emmiegit Sep 29, 2023
989bee3
Use iter.take(1) to avoid splitting mutable argument vector.
emmiegit Sep 29, 2023
8646c7f
Only import used items from notify crate.
emmiegit Sep 29, 2023
6c43381
Add separate build step for local / deploy features.
emmiegit Sep 29, 2023
5a9d6b5
Use direct notify crate to switch to PollWatcher.
emmiegit Sep 29, 2023
480f92b
Fix compile on non-watch.
emmiegit Sep 29, 2023
64eaf39
Remove cargo watch lines because of new flag.
emmiegit Sep 29, 2023
f333dab
Use RecommendedWatcher.
emmiegit Sep 29, 2023
b5f80e3
Revert to cargo watch invocation.
emmiegit Sep 29, 2023
7e659cc
Fix argument in README.
emmiegit Sep 29, 2023
5324973
Note lack of operation via Docker.
emmiegit Sep 29, 2023
3b50c6b
Remove void crate.
emmiegit Sep 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/deepwell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ jobs:
- name: System Dependencies
run: sudo apt update && sudo apt install libmagic-dev

- name: Build
run: cd deepwell && cargo build
- name: Build (local)
run: cd deepwell && cargo build --features local

- name: Build (deploy)
run: cd deepwell && cargo build --features deploy

- name: Check Configuration
run: cd deepwell && cargo run -- config.example.toml ../install/files/local/deepwell.toml
Expand Down
113 changes: 113 additions & 0 deletions deepwell/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions deepwell/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ version = "2023.5.14"
authors = ["Emmie Maeda <[email protected]>"]
edition = "2021" # this is *not* the same as the current year

[features]
local = ["watch"]
deploy = []
watch = ["notify"]

[dependencies]
anyhow = "1"
arraystring = "0.3"
argon2 = "0.5"
async-std = { version = "1", features = ["attributes"] }
cfg-if = "1"
clap = "4"
color-backtrace = "0.6"
crossfire = "1.0"
Expand All @@ -32,6 +38,7 @@ hex = "0.4"
hostname = "0.3"
intl-memoizer = "0.5"
lazy_static = "1"
notify = { version = "6", optional = true }
otp = { git = "https://github.com/TimDumol/rust-otp" }
rand = "0.8"
ref-map = "0.1"
Expand Down
30 changes: 28 additions & 2 deletions deepwell/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ $ scripts/generate-models.sh
The primary organization of the crate is as follows:

* `api/` &mdash; Web server definition, such as its routes and related structures.
* Each API is namespaced based on its version. The primary version of interest is the "internal" API, which is consumed by PHP and not meant for outside consumption due to it providing unguarded access.
* Exposes the internal API for use by Framerail.
* `endpoints/` &mdash; Implementations for individual endpoints described above.
* `services/` &mdash; "Services", or logical encapsulations of different concepts or operations.
* For instance, the `ParentService` allows retrieving and storing data related to parent-child page relationships. You can think of it as "wrapping" the `page_parent` table.
Expand All @@ -54,10 +54,36 @@ The routes are defined in `api/`, with their implementations in `methods/`, and

This executable targets the latest stable Rust. At time of writing, that is `1.72.0`.

There are two features supported by DEEPWELL, along with what they add:

* `local` &mdash; Intended for local development, where frequent compilation is likely.
* Tracks the locale directory and configuration file, reloading them if they are modified.
* `deploy` &mdash; Intended for "deployed" environments, i.e. `dev` and `prod`.

Thus for a _release build_ (being deployed somewhere) you would want to run:

```sh
$ cargo build --release --features deploy
```

And for a _local build_ you would want:

```sh
$ cargo build --release
$ cargo build --features local
```

### Execution

```sh
$ cargo build --features <deploy|local> -- [-q] [-p <port>] <config-file>
```

There are a number of arguments beyond the ones shown. Run with `--help` for all relevant information.

This runs a local instance of DEEPWELL with the given configuration file. When debugging (i.e. on `--features local` only), you can also pass in `-w` or `--watch-files` to have the process to restart automatically when the configuration file or any localization files change.

This does not seem to work with Docker, so you should instead manually stop the `api` container and run it locally with the flag. That will properly watch changes and restart itself.

### Testing

Tests have not yet been implemented, but when they are, run:
Expand Down
4 changes: 2 additions & 2 deletions deepwell/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ authentication-fail-delay-ms = 100
[security.session]

# All session tokens are prefixed with this string.
# It makes a session token immediately reecognizable
# It makes a session token immediately recognizable
# as it is otherwise a long random string.
token-prefix = "wj:"

Expand Down Expand Up @@ -246,7 +246,7 @@ maximum-name-changes = 3
# The minimum length for a user's name in bytes.
# A user who attempts to register must have a slug which is at least this long.
#
# The intent is to prevent the proliferation of very short, unidentifiable usernames
# The intent is to prevent the proliferation of very short, unidentifiable usernames
# such as single Latin letters (e.g. "N"). However, we check *bytes* specifically to
# avoid Anglo-centricism, as many full names in other languages fit within two letters
# (consider CJK for instance). Single characters outside of the main ASCII block
Expand Down
1 change: 1 addition & 0 deletions deepwell/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ fn build_routes(mut app: ApiServer) -> ApiServer {
app.at("/version/full").get(full_version);
app.at("/hostname").get(hostname);
app.at("/config").get(config_dump);
app.at("/config/path").get(config_path);
app.at("/normalize/:input").all(normalize_method);
app.at("/teapot")
.all(|_| async { error_response(StatusCode::ImATeapot, "🫖") });
Expand Down
13 changes: 12 additions & 1 deletion deepwell/src/config/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ pub fn parse_args() -> Config {
.action(ArgAction::Set)
.help("What port to listen on."),
)
.arg(
Arg::new("watch-config")
.short('w')
.long("watch")
.action(ArgAction::SetTrue)
.help("Whether to auto-restart when configuration or localization files change."),
)
.arg(
Arg::new("run-migrations")
.short('M')
Expand Down Expand Up @@ -119,7 +126,7 @@ pub fn parse_args() -> Config {
.remove_one::<PathBuf>("config-file")
.expect("Required argument not provided");

let mut config = match Config::load(&config_path) {
let mut config = match Config::load(config_path) {
Ok(config) => config,
Err(error) => {
eprintln!("Unable to load configuration from file: {error}");
Expand Down Expand Up @@ -151,6 +158,10 @@ pub fn parse_args() -> Config {
config.address.set_port(value);
}

if matches.remove_one::<bool>("watch-config") == Some(true) {
config.watch_files = true;
}

if let Some(value) = matches.remove_one::<bool>("run-migrations") {
config.run_migrations = value;
}
Expand Down
Loading