fix: hotpatching fullstack (#4730)
* fix: hotpatching fullstack * add hot-patching fullstack test * add caching to playwright apt-get * only run playwright on beta * install binutils? * dont commit lockfile * ignore lockfiles * make sure ld is in path
This commit is contained in:
1 parent
a4aef33369
commit
bee89b795d
15 files changed
+265
-38
No files matched your search
@@ -715,7 +715,7 @@ impl AppBuilder {
|
||||
|
||||
let changed_file = changed_files.first().unwrap();
|
||||
tracing::info!(
|
||||
"Hot-patching: {NOTE_STYLE}{}{NOTE_STYLE:#} took {GLOW_STYLE}{:?}ms{GLOW_STYLE:#} ({})",
|
||||
"Hot-patching: {NOTE_STYLE}{}{NOTE_STYLE:#} took {GLOW_STYLE}{:?}ms{GLOW_STYLE:#}",
|
||||
changed_file
|
||||
.display()
|
||||
.to_string()
|
||||
@@ -723,8 +723,7 @@ impl AppBuilder {
|
||||
SystemTime::now()
|
||||
.duration_since(res.time_start)
|
||||
.unwrap()
|
||||
.as_millis(),
|
||||
triple
|
||||
.as_millis()
|
||||
);
|
||||
|
||||
self.patches.push(jump_table.clone());
|
||||
|
||||
@@ -175,27 +175,18 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &TraceController) -> Resu
|
||||
}
|
||||
BuilderUpdate::BuildReady { bundle } => match bundle.mode {
|
||||
BuildMode::Thin { ref cache, .. } => {
|
||||
let elapsed =
|
||||
bundle.time_end.duration_since(bundle.time_start).unwrap();
|
||||
match builder.hotpatch(&bundle, id, cache).await {
|
||||
Ok(jumptable) => {
|
||||
let pid = match id {
|
||||
BuildId::CLIENT => builder.client.pid,
|
||||
_ => builder.server.as_ref().and_then(|s| s.pid),
|
||||
};
|
||||
devserver.send_patch(jumptable, elapsed, id, pid).await
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("Failed to hot-patch app: {err}");
|
||||
if let Err(err) =
|
||||
builder.hotpatch(&bundle, id, cache, &mut devserver).await
|
||||
{
|
||||
tracing::error!("Failed to hot-patch app: {err}");
|
||||
|
||||
if let Some(_patching) =
|
||||
err.downcast_ref::<crate::build::PatchError>()
|
||||
{
|
||||
tracing::info!("Starting full rebuild: {err}");
|
||||
builder.full_rebuild().await;
|
||||
devserver.send_reload_start().await;
|
||||
devserver.start_build().await;
|
||||
}
|
||||
if let Some(_patching) =
|
||||
err.downcast_ref::<crate::build::PatchError>()
|
||||
{
|
||||
tracing::info!("Starting full rebuild: {err}");
|
||||
builder.full_rebuild().await;
|
||||
devserver.send_reload_start().await;
|
||||
devserver.start_build().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ use std::{
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use subsecond_types::JumpTable;
|
||||
use syn::spanned::Spanned;
|
||||
use tokio::process::Command;
|
||||
|
||||
@@ -53,7 +52,7 @@ pub(crate) struct AppServer {
|
||||
pub(crate) watcher_rx: UnboundedReceiver<notify::Event>,
|
||||
|
||||
// Tracked state related to open builds and hot reloading
|
||||
pub(crate) applied_hot_reload_message: HotReloadMsg,
|
||||
pub(crate) applied_client_hot_reload_message: HotReloadMsg,
|
||||
pub(crate) file_map: HashMap<PathBuf, CachedFile>,
|
||||
|
||||
// Resolved args related to how we go about processing the rebuilds and logging
|
||||
@@ -185,7 +184,7 @@ impl AppServer {
|
||||
// Create the runner
|
||||
let mut runner = Self {
|
||||
file_map: Default::default(),
|
||||
applied_hot_reload_message: Default::default(),
|
||||
applied_client_hot_reload_message: Default::default(),
|
||||
automatic_rebuilds: true,
|
||||
watch_fs,
|
||||
use_hotpatch_engine,
|
||||
@@ -709,27 +708,66 @@ impl AppServer {
|
||||
|
||||
pub(crate) async fn hotpatch(
|
||||
&mut self,
|
||||
res: &BuildArtifacts,
|
||||
bundle: &BuildArtifacts,
|
||||
id: BuildId,
|
||||
cache: &HotpatchModuleCache,
|
||||
) -> Result<JumpTable> {
|
||||
devserver: &mut WebServer,
|
||||
) -> Result<()> {
|
||||
let elapsed = bundle
|
||||
.time_end
|
||||
.duration_since(bundle.time_start)
|
||||
.unwrap_or_default();
|
||||
|
||||
let jump_table = match id {
|
||||
BuildId::CLIENT => self.client.hotpatch(res, cache).await,
|
||||
BuildId::CLIENT => self.client.hotpatch(bundle, cache).await,
|
||||
BuildId::SERVER => {
|
||||
self.server
|
||||
.as_mut()
|
||||
.context("Server not found")?
|
||||
.hotpatch(res, cache)
|
||||
.hotpatch(bundle, cache)
|
||||
.await
|
||||
}
|
||||
_ => bail!("Invalid build id"),
|
||||
}?;
|
||||
|
||||
if id == BuildId::CLIENT {
|
||||
self.applied_hot_reload_message.jump_table = self.client.patches.last().cloned();
|
||||
self.applied_client_hot_reload_message.jump_table = self.client.patches.last().cloned();
|
||||
}
|
||||
|
||||
Ok(jump_table)
|
||||
// If no server, just send the patch immediately
|
||||
let Some(server) = self.server.as_mut() else {
|
||||
devserver
|
||||
.send_patch(jump_table, elapsed, id, self.client.pid)
|
||||
.await;
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// If we have a server, we need to wait until both the client and server are ready
|
||||
// Otherwise we end up with an annoying race condition where the client can't actually load the patch
|
||||
if self.client.stage == BuildStage::Success && server.stage == BuildStage::Success {
|
||||
let client_jump_table = self
|
||||
.client
|
||||
.patches
|
||||
.last()
|
||||
.cloned()
|
||||
.context("Missing client jump table")?;
|
||||
|
||||
let server_jump_table = server
|
||||
.patches
|
||||
.last()
|
||||
.cloned()
|
||||
.context("Missing server jump table")?;
|
||||
|
||||
devserver
|
||||
.send_patch(server_jump_table, elapsed, BuildId::SERVER, server.pid)
|
||||
.await;
|
||||
|
||||
devserver
|
||||
.send_patch(client_jump_table, elapsed, BuildId::CLIENT, self.client.pid)
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_build(&self, id: BuildId) -> Option<&AppBuilder> {
|
||||
@@ -751,7 +789,7 @@ impl AppServer {
|
||||
|
||||
/// Get any hot reload changes that have been applied since the last full rebuild
|
||||
pub(crate) fn applied_hot_reload_changes(&mut self, build: BuildId) -> HotReloadMsg {
|
||||
let mut msg = self.applied_hot_reload_message.clone();
|
||||
let mut msg = self.applied_client_hot_reload_message.clone();
|
||||
|
||||
if build == BuildId::CLIENT {
|
||||
msg.jump_table = self.client.patches.last().cloned();
|
||||
@@ -773,7 +811,7 @@ impl AppServer {
|
||||
|
||||
/// Clear the hot reload changes. This should be called any time a new build is starting
|
||||
pub(crate) fn clear_hot_reload_changes(&mut self) {
|
||||
self.applied_hot_reload_message = Default::default();
|
||||
self.applied_client_hot_reload_message = Default::default();
|
||||
}
|
||||
|
||||
pub(crate) fn clear_patches(&mut self) {
|
||||
@@ -836,7 +874,7 @@ impl AppServer {
|
||||
|
||||
/// Store the hot reload changes for any future clients that connect
|
||||
fn add_hot_reload_message(&mut self, msg: &HotReloadMsg) {
|
||||
let applied = &mut self.applied_hot_reload_message;
|
||||
let applied = &mut self.applied_client_hot_reload_message;
|
||||
|
||||
// Merge the assets, unknown files, and templates
|
||||
// We keep the newer change if there is both a old and new change
|
||||
|
||||
Reference in new issue
Block a user