Skip to content

Commit

Permalink
fix(serverless): drop isolates in the same thread as they were created (
Browse files Browse the repository at this point in the history
  • Loading branch information
QuiiBz authored Jan 14, 2023
1 parent 2430e11 commit 9468c1f
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/fast-geese-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lagon/serverless': patch
---

Drop and exit isolates in the same thread as they were created
3 changes: 2 additions & 1 deletion crates/serverless/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"private": true,
"scripts": {
"build": "cargo build",
"lint": "cargo clippy -- -Dwarnings --no-deps"
"lint": "cargo clippy -- -Dwarnings --no-deps",
"debug": "cargo build && rust-lldb ../../target/debug/lagon-serverless"
}
}
42 changes: 31 additions & 11 deletions crates/serverless/src/deployments/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@ use std::{
time::{Duration, Instant},
};

use log::info;
use log::{error, info};
use tokio::sync::RwLock;
use tokio_util::task::LocalPoolHandle;

use crate::ISOLATES;

const CACHE_TASK_INTERVAL: Duration = Duration::from_secs(60);

pub fn run_cache_clear_task(last_requests: Arc<RwLock<HashMap<String, Instant>>>) {
pub fn run_cache_clear_task(
last_requests: Arc<RwLock<HashMap<String, Instant>>>,
thread_ids: Arc<RwLock<HashMap<String, usize>>>,
pool: LocalPoolHandle,
) {
let isolates_cache_seconds = Duration::from_secs(
env::var("LAGON_ISOLATES_CACHE_SECONDS")
.expect("LAGON_ISOLATES_CACHE_SECONDS is not set")
Expand All @@ -28,8 +33,6 @@ pub fn run_cache_clear_task(last_requests: Arc<RwLock<HashMap<String, Instant>>>
let mut isolates_to_clear = Vec::new();
let last_requests_reader = last_requests.read().await;

info!("Running cache clear task");

for (hostname, last_request) in last_requests_reader.iter() {
if now.duration_since(*last_request) > isolates_cache_seconds {
isolates_to_clear.push(hostname.clone());
Expand All @@ -43,20 +46,37 @@ pub fn run_cache_clear_task(last_requests: Arc<RwLock<HashMap<String, Instant>>>
// Drop the read lock because we now acquire a write lock
drop(last_requests_reader);

let mut thread_isolates = ISOLATES.write().await;
let mut last_requests = last_requests.write().await;
let thread_ids = thread_ids.read().await;

for hostname in isolates_to_clear {
for isolates in thread_isolates.values_mut() {
if let Some(thread_id) = thread_ids.get(&hostname) {
last_requests.remove(&hostname);

if let Some(isolate) = isolates.remove(&hostname) {
let metadata = isolate.get_metadata();
let thread_id = *thread_id;

// The isolate is implicitely dropped when the block after `remove()` ends
//
// An isolate must be dropped (which will call `exit()` and terminate the
// execution) in the same thread as it was created in
match pool.spawn_pinned_by_idx(move || async move {
let mut thread_isolates = ISOLATES.write().await;
let thread_isolates = thread_isolates.get_mut(&thread_id).unwrap();

if let Some(isolate) = thread_isolates.remove(&hostname) {
let metadata = isolate.get_metadata();

if let Some((deployment, ..)) = metadata.as_ref() {
info!(deployment = deployment; "Clearing deployment from cache due to expiration");
if let Some((deployment, ..)) = metadata.as_ref() {
info!(deployment = deployment; "Clearing deployment from cache due to expiration");
}
}
}
}, thread_id)
.await {
Ok(_) => {},
Err(err) => {
error!("Failed to clear deployment from cache: {}", err);
}
};
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions crates/serverless/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,11 +396,15 @@ async fn main() -> Result<()> {
let deployments = get_deployments(conn, bucket.clone()).await?;
let redis = listen_pub_sub(bucket.clone(), Arc::clone(&deployments));
let last_requests = Arc::new(RwLock::new(HashMap::new()));
run_cache_clear_task(Arc::clone(&last_requests));

let pool = LocalPoolHandle::new(POOL_SIZE);
let thread_ids = Arc::new(RwLock::new(HashMap::new()));

run_cache_clear_task(
Arc::clone(&last_requests),
Arc::clone(&thread_ids),
pool.clone(),
);

let server = Server::bind(&addr).serve(make_service_fn(move |conn: &AddrStream| {
let deployments = Arc::clone(&deployments);
let pool = pool.clone();
Expand Down

2 comments on commit 9468c1f

@vercel
Copy link

@vercel vercel bot commented on 9468c1f Jan 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deployment failed with the following error:

Resource is limited - try again in 41 minutes (more than 100, code: "api-deployments-free-per-day").

@vercel
Copy link

@vercel vercel bot commented on 9468c1f Jan 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deployment failed with the following error:

Resource is limited - try again in 40 minutes (more than 100, code: "api-deployments-free-per-day").

Please sign in to comment.