ENEREHTW2UEXJGIOSSKZA2FQKFDLWQEIOAD6NIT2EH6BJW6E3AZQC
*db_.lock().await = Some(db);
let e = connection.await;
eprintln!("connection ended: {:?}", e);
// Ignore "normal" restarts (i.e. promotes).
let db = db_.lock().await.take();
if db.is_some() {
lead_.send(false).unwrap();
*db_.lock().await = None;
} else {
debug!("normal restart, reconnecting");
is_normal = true;
Err(e) => {
error!("{:?}", e);
lead_.send(String::new()).unwrap();
let mut race = tokio::spawn(race(host.clone(), signal.clone(), is_leader.clone()));
// let addr = SocketAddr::from((
// [0, 0, 0, 0],
// matches
// .value_of("port")
// .and_then(|x| x.parse().ok())
// .unwrap_or(8008),
// ));
let mut race = tokio::spawn(race(host.clone(), is_leader.clone()));
let mut was_leader = {
if let Some(pool_) = pool.lock().await.take() {
let row = pool_.query_one("SELECT pg_is_in_recovery()", &[]).await?;
let is_in_recovery: bool = row.get(0);
*pool.lock().await = Some(pool_);
Some(!is_in_recovery)
} else {
None
}
};
debug!("was_leader = {:?}", was_leader);
if leader == host {
info!("promoting");
pool_.execute("SELECT pg_promote()", &[]).await.unwrap_or(0);
// Don't replace pool_ into *pool, since the server might restart.
*pool.lock().await = Some(pool_)
} else {
*pool.lock().await = Some(pool_)
}
} else {
lead.send(false)?;
*pool.lock().await = Some(pool_);
}
if is_leader && was_leader != Some(true) {
promote(&path).await
} else if !is_leader && was_leader == Some(true) {
rewind(&path, port, &db_name, &leader).await
async fn rewind(path: &str, port: u16, db_name: &str, leader: &str) {
use tokio::process::Command;
Command::new("systemctl")
.args(["stop", "postgresql-repl"])
.output()
.await
.expect("failed to execute process");
Command::new("pg_rewind")
.args([
"-D",
&path,
"-R",
"--source-server",
&format!(
"port={} user=postgres dbname={} host={}",
port, db_name, leader
),
])
.output()
.await
.expect("failed to execute process");
Command::new("systemctl")
.args(["start", "postgresql-repl"])
.output()
.await
.expect("failed to execute process");
}
### Cooperation from the OS
The same user must run the PostgreSQL server and this tool. If that user is called `postgres`, here is a possible PolicyKit rule to make it work:
``` js
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "postgresql-repl.service" &&
subject.user == "postgres"){
return polkit.Result.YES;
}
});
```