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

Plugin may need more than 2 seconds to start #240

Closed
madeye opened this issue May 7, 2020 · 2 comments
Closed

Plugin may need more than 2 seconds to start #240

madeye opened this issue May 7, 2020 · 2 comments

Comments

@madeye
Copy link
Contributor

madeye commented May 7, 2020

On some old Android device, we expect plugins like v2ray would have a very slow startup, which will break the assumption below:

// Try to connect plugin 10 times (nearly 2 seconds)

Here's the bug report for shadowsocks-android:

shadowsocks/shadowsocks-android#2515 (comment)

We may wait longer enough, say 10 seconds, or just remove this connection test in shadowsocks-rust.

BTW, I expect even slower startup on some embedded devices like routers.

@zonyitoo
Copy link
Collaborator

zonyitoo commented May 8, 2020

That's bad. :(

Those code were added for ensuring that when server's port is listening, server is ready for accepting requests.

Also, the LoadBalancer requires initialization for choosing the best server. If removing this, LoadBalancer's constructor won't be able to know which server is dead.

pub async fn new(context: SharedContext, server_type: ServerType) -> PingBalancer<S> {
let server_count = context.config().server.len();
let mut servers = Vec::with_capacity(server_count);
// Check only required if servers count > 1, otherwise, always use the first one
let check_required = server_count > 1;
// Barrier count = current + probing tasks
let check_barrier = Arc::new(Barrier::new(1 + server_count));
for idx in 0..server_count {
let stat = ServerStatistic::<S>::new_shared(context.clone(), idx);
if check_required {
let stat = stat.clone();
let context = context.clone();
let check_barrier = check_barrier.clone();
// Start a background task for probing
tokio::spawn(async move {
// Check once for initializing data
PingBalancer::<S>::check_update_score(&stat, server_type).await;
trace!(
"started latency probing task for server {}, initial score {}",
stat.server_config().addr(),
stat.score().await,
);
check_barrier.wait().await;
while context.server_running() {
PingBalancer::<S>::check_update_score(&stat, server_type).await;
time::delay_for(Duration::from_secs(DEFAULT_CHECK_INTERVAL_SEC)).await;
}
debug!(
"probing task for remote {} server {} exited",
server_type,
stat.server_config().addr()
);
});
}
servers.push(stat);
}
let best = BestServer::new_shared(servers);
if check_required {
// Wait all tasks start (run at least one round)
check_barrier.wait().await;
trace!("all latency probing tasks are started, creating best server choosing task");
// Reinitialize a Barrier for waiting choosing task
let check_barrier = Arc::new(Barrier::new(2));
let best = best.clone();
{
let context = context.clone();
let check_barrier = check_barrier.clone();
tokio::spawn(async move {
// Check once for initializing data
best.recalculate_best_server().await;
trace!(
"started best server choosing task, chosen server index {}",
best.best_server_idx()
);
check_barrier.wait().await;
while context.server_running() {
if let Some((old_idx, new_idx)) = best.recalculate_best_server().await {
info!(
"switched {} server from {} to {}",
server_type,
context.server_config(old_idx).addr(),
context.server_config(new_idx).addr()
);
}
time::delay_for(Duration::from_secs(DEFAULT_CHECK_INTERVAL_SEC)).await;
}
});
}
// Wait for choosing task to check at least once
check_barrier.wait().await;
}
PingBalancer { best }
}

Both of them will eventually cause failures just after launch.

@zonyitoo
Copy link
Collaborator

zonyitoo commented May 8, 2020

We may wait longer enough, say 10 seconds.

I would prefer that.

And don't crash if any plugins don't response in time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants