Skip to content

Commit

Permalink
Reuse canisters of deleted empty and dormant users (#6046)
Browse files Browse the repository at this point in the history
  • Loading branch information
hpeebles authored Jul 17, 2024
1 parent 3d4d816 commit f086794
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 22 deletions.
1 change: 1 addition & 0 deletions backend/canisters/local_user_index/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added

- Support gates with multiple verifiable credentials ([#6029](https://github.com/open-chat-labs/open-chat/pull/6029))
- Reuse canisters of deleted empty and dormant users ([#6046](https://github.com/open-chat-labs/open-chat/pull/6046))

### Changed

Expand Down
12 changes: 7 additions & 5 deletions backend/canisters/local_user_index/impl/src/jobs/delete_users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ use ic_cdk_timers::TimerId;
use std::cell::Cell;
use std::time::Duration;
use tracing::trace;
use types::Empty;
use types::{Empty, Milliseconds};
use user_index_canister::{Event, UserDeleted};
use utils::time::SECOND_IN_MS;

thread_local! {
static TIMER_ID: Cell<Option<TimerId>> = Cell::default();
}

pub(crate) fn start_job_if_required(state: &RuntimeState) -> bool {
pub(crate) fn start_job_if_required(state: &RuntimeState, delay: Option<Milliseconds>) -> bool {
if TIMER_ID.get().is_none() && !state.data.users_to_delete_queue.is_empty() {
let timer_id = ic_cdk_timers::set_timer(Duration::ZERO, run);
let timer_id = ic_cdk_timers::set_timer(Duration::from_millis(delay.unwrap_or_default()), run);
TIMER_ID.set(Some(timer_id));
true
} else {
Expand Down Expand Up @@ -42,7 +43,7 @@ async fn process_user(user: UserToDelete) {
match user_canister_c2c_client::c2c_is_empty_and_dormant(canister_id, &Empty {}).await {
Ok(true) => {}
Ok(false) => {
read_state(start_job_if_required);
read_state(|state| start_job_if_required(state, None));
return;
}
Err(_) => error = true,
Expand All @@ -60,6 +61,7 @@ async fn process_user(user: UserToDelete) {

if !user.triggered_by_user {
state.push_event_to_user_index(Event::UserDeleted(Box::new(UserDeleted { user_id })));
state.data.canister_pool.push(canister_id);
}
} else if user.attempt < 50 {
state.data.users_to_delete_queue.push_back(UserToDelete {
Expand All @@ -69,6 +71,6 @@ async fn process_user(user: UserToDelete) {
});
}

start_job_if_required(state);
start_job_if_required(state, error.then_some(30 * SECOND_IN_MS));
})
}
2 changes: 1 addition & 1 deletion backend/canisters/local_user_index/impl/src/jobs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub mod topup_canister_pool;
pub mod upgrade_canisters;

pub(crate) fn start(state: &RuntimeState) {
delete_users::start_job_if_required(state);
delete_users::start_job_if_required(state, None);
make_btc_miami_payments::start_job_if_required(state);
sync_events_to_user_canisters::start_job_if_required(state);
sync_events_to_user_index_canister::start_job_if_required(state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ fn handle_event(event: Event, state: &mut RuntimeState) {
triggered_by_user: ev.triggered_by_user,
attempt: 0,
});
jobs::delete_users::start_job_if_required(state);
jobs::delete_users::start_job_if_required(state, None);
} else {
state.data.global_users.remove(&ev.user_id);
}
Expand Down
1 change: 1 addition & 0 deletions backend/canisters/user/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Added lots more achievements to enum ([#6020](https://github.com/open-chat-labs/open-chat/pull/6020))
- Added support for a bunch more achievements ([#6033](https://github.com/open-chat-labs/open-chat/pull/6033))
- Store `unique_person_proof` in User canisters ([#6029](https://github.com/open-chat-labs/open-chat/pull/6029))
- Re-enable notifying of user accounts that are empty and dormant ([#6046](https://github.com/open-chat-labs/open-chat/pull/6046))

### Removed

Expand Down
26 changes: 11 additions & 15 deletions backend/canisters/user/impl/src/lifecycle/post_upgrade.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::lifecycle::{init_env, init_state};
use crate::memory::get_upgrades_memory;
use crate::{mutate_state, Data};
use crate::{read_state, Data};
use canister_logger::LogEntry;
use canister_tracing_macros::trace;
use ic_cdk::post_upgrade;
Expand All @@ -12,7 +12,6 @@ use user_canister::post_upgrade::Args;
use utils::time::DAY_IN_MS;

const SIX_MONTHS: Milliseconds = 183 * DAY_IN_MS;
const NOTIFY_IF_EMPTY: bool = false;

#[post_upgrade]
#[trace]
Expand All @@ -29,22 +28,19 @@ fn post_upgrade(args: Args) {

info!(version = %args.wasm_version, "Post-upgrade complete");

// Disable this for now until all existing empty users have been deleted
if NOTIFY_IF_EMPTY {
mutate_state(|state| {
if state.data.user_created + SIX_MONTHS < state.env.now()
&& state.data.direct_chats.len() <= 1
&& state.data.group_chats.len() == 0
&& state.data.communities.len() == 0
{
ic_cdk_timers::set_timer(Duration::ZERO, mark_user_canister_empty);
}
});
}
read_state(|state| {
if state.data.user_created + SIX_MONTHS < state.env.now()
&& state.data.direct_chats.len() <= 1
&& state.data.group_chats.len() == 0
&& state.data.communities.len() == 0
{
ic_cdk_timers::set_timer(Duration::ZERO, mark_user_canister_empty);
}
});
}

fn mark_user_canister_empty() {
mutate_state(|state| {
read_state(|state| {
let user_index_canister_id = state.data.user_index_canister_id;
state.data.fire_and_forget_handler.send(
user_index_canister_id,
Expand Down
1 change: 1 addition & 0 deletions backend/canisters/user_index/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

- Sync userIds to Identity canister ([#6027](https://github.com/open-chat-labs/open-chat/pull/6027))
- Add `is_unique_person` field to user responses ([#6040](https://github.com/open-chat-labs/open-chat/pull/6040))
- Auto delete users who get flagged as being empty and dormant ([#6046](https://github.com/open-chat-labs/open-chat/pull/6046))

## [[2.0.1235](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.1235-user_index)] - 2024-07-11

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{mutate_state, RuntimeState};
use canister_api_macros::update;
use canister_tracing_macros::trace;
use local_user_index_canister::{DeleteUser, Event};
use user_index_canister::c2c_mark_user_canister_empty::{Response::*, *};

#[update(msgpack = true)]
Expand All @@ -13,6 +14,13 @@ fn c2c_mark_user_canister_empty_impl(state: &mut RuntimeState) -> Response {
let user_id = state.env.caller().into();
if state.data.users.get_by_user_id(&user_id).is_some() {
state.data.empty_users.insert(user_id);
state.push_event_to_all_local_user_indexes(
Event::DeleteUser(DeleteUser {
user_id,
triggered_by_user: false,
}),
None,
);
}
Success
}
4 changes: 4 additions & 0 deletions backend/libraries/utils/src/canister/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ impl Pool {
self.canister_ids.len() >= self.target_size as usize
}

pub fn contains(&self, canister_id: &CanisterId) -> bool {
self.canister_ids.contains(canister_id)
}

pub fn push(&mut self, canister_id: CanisterId) {
self.canister_ids.push_back(canister_id);
}
Expand Down

0 comments on commit f086794

Please sign in to comment.