Compare commits
6
Commits
v2026.9.30.1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c43abef8ab | ||
|
|
c9f8028502 | ||
|
|
cd7a0f4163 | ||
|
|
30d4cef0e7 | ||
|
|
6c1eeea038 | ||
|
|
ea9a6f0c58 |
@@ -357,18 +357,23 @@ jobs:
|
|||||||
cat SHA256SUMS
|
cat SHA256SUMS
|
||||||
# A re-run of a tag replaces its assets rather than leaving two files
|
# A re-run of a tag replaces its assets rather than leaving two files
|
||||||
# with the same name and different contents.
|
# with the same name and different contents.
|
||||||
|
#
|
||||||
|
# The uploads cross Cloudflare, which dropped 50 MB HTTP/2 uploads
|
||||||
|
# part-way for v2026.9.30.1 (curl 92, PROTOCOL_ERROR; origin logged
|
||||||
|
# 400), once on each of two runs. Uploads go over HTTP/1.1 and retry.
|
||||||
- name: attach them to the release
|
- name: attach them to the release
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
api="$GITEA_URL/api/v1/repos/$GITHUB_REPOSITORY"
|
api="$GITEA_URL/api/v1/repos/$GITHUB_REPOSITORY"
|
||||||
auth="Authorization: token $GITEA_TOKEN"
|
auth="Authorization: token $GITEA_TOKEN"
|
||||||
rel="$(curl -fsS -H "$auth" "$api/releases/tags/$TAG" | jq -r .id)"
|
retry=(--retry 5 --retry-all-errors --retry-delay 15)
|
||||||
assets="$(curl -fsS -H "$auth" "$api/releases/$rel/assets")"
|
rel="$(curl -fsS "${retry[@]}" -H "$auth" "$api/releases/tags/$TAG" | jq -r .id)"
|
||||||
|
assets="$(curl -fsS "${retry[@]}" -H "$auth" "$api/releases/$rel/assets")"
|
||||||
for f in out/inbuxa-linux-amd64.tar.gz out/inbuxa-linux-arm64.tar.gz out/SHA256SUMS; do
|
for f in out/inbuxa-linux-amd64.tar.gz out/inbuxa-linux-arm64.tar.gz out/SHA256SUMS; do
|
||||||
name="$(basename "$f")"
|
name="$(basename "$f")"
|
||||||
old="$(jq -r --arg n "$name" '.[] | select(.name == $n) | .id' <<<"$assets")"
|
old="$(jq -r --arg n "$name" '.[] | select(.name == $n) | .id' <<<"$assets")"
|
||||||
for id in $old; do curl -fsS -o /dev/null -X DELETE -H "$auth" "$api/releases/$rel/assets/$id"; done
|
for id in $old; do curl -fsS "${retry[@]}" -o /dev/null -X DELETE -H "$auth" "$api/releases/$rel/assets/$id"; done
|
||||||
curl -fsS -o /dev/null -X POST -H "$auth" -F "attachment=@$f" "$api/releases/$rel/assets?name=$name"
|
curl -fsS --http1.1 "${retry[@]}" -o /dev/null -X POST -H "$auth" -F "attachment=@$f" "$api/releases/$rel/assets?name=$name"
|
||||||
echo "attached $name"
|
echo "attached $name"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -116,8 +116,19 @@ impl StoredMetric {
|
|||||||
/// changes (MON-4). Per process: a restart counts from the start.
|
/// changes (MON-4). Per process: a restart counts from the start.
|
||||||
static LAST: Mutex<Option<AHashMap<MetricType, (u64, u64)>>> = Mutex::new(None);
|
static LAST: Mutex<Option<AHashMap<MetricType, (u64, u64)>>> = Mutex::new(None);
|
||||||
|
|
||||||
/// One tick's samples (MON-4 to MON-6).
|
/// Gauges that count the whole cluster's data, not this node's. Only the node
|
||||||
pub fn sample() -> Vec<Metric> {
|
/// that computes them (the metrics-calculation role) has a true reading; on
|
||||||
|
/// the others the queue gauge only moves with local queue events and drifts
|
||||||
|
/// below zero, and the account and domain counts stay at 0.
|
||||||
|
const CLUSTER_GAUGES: [MetricType; 3] = [
|
||||||
|
MetricType::QueueCount,
|
||||||
|
MetricType::UserCount,
|
||||||
|
MetricType::DomainCount,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// One tick's samples (MON-4 to MON-6). `calculates` is whether this node
|
||||||
|
/// computes the cluster-wide gauges; a node that doesn't leaves them out.
|
||||||
|
pub fn sample(calculates: bool) -> Vec<Metric> {
|
||||||
let mut last_guard = LAST.lock().unwrap();
|
let mut last_guard = LAST.lock().unwrap();
|
||||||
let last = last_guard.get_or_insert_with(AHashMap::new);
|
let last = last_guard.get_or_insert_with(AHashMap::new);
|
||||||
let mut samples = Vec::new();
|
let mut samples = Vec::new();
|
||||||
@@ -140,6 +151,9 @@ pub fn sample() -> Vec<Metric> {
|
|||||||
|
|
||||||
// Gauges: the reading, always (MON-5)
|
// Gauges: the reading, always (MON-5)
|
||||||
for gauge in Collector::collect_gauges() {
|
for gauge in Collector::collect_gauges() {
|
||||||
|
if !calculates && CLUSTER_GAUGES.contains(&gauge.id()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
samples.push(Metric::Gauge(MetricCount {
|
samples.push(Metric::Gauge(MetricCount {
|
||||||
count: gauge.get(),
|
count: gauge.get(),
|
||||||
metric: gauge.id(),
|
metric: gauge.id(),
|
||||||
@@ -181,7 +195,7 @@ impl Server {
|
|||||||
if store.is_none() {
|
if store.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let samples = sample();
|
let samples = sample(self.core.network.roles.metrics_calculate);
|
||||||
let count = samples.len();
|
let count = samples.len();
|
||||||
let started = std::time::Instant::now();
|
let started = std::time::Instant::now();
|
||||||
match store.write_metrics(samples, now()).await {
|
match store.write_metrics(samples, now()).await {
|
||||||
@@ -271,3 +285,41 @@ impl Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn gauges(samples: &[Metric]) -> Vec<MetricType> {
|
||||||
|
samples
|
||||||
|
.iter()
|
||||||
|
.filter_map(|m| match m {
|
||||||
|
Metric::Gauge(g) => Some(g.metric),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn only_the_calculating_node_stores_cluster_gauges() {
|
||||||
|
let all = gauges(&sample(true));
|
||||||
|
let local = gauges(&sample(false));
|
||||||
|
for metric in CLUSTER_GAUGES {
|
||||||
|
assert!(
|
||||||
|
all.contains(&metric),
|
||||||
|
"{metric:?} missing on the calculating node"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!local.contains(&metric),
|
||||||
|
"{metric:?} stored by a node that doesn't compute it"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Per-node gauges are stored either way
|
||||||
|
for metric in [MetricType::ServerMemory, MetricType::HttpActiveConnections] {
|
||||||
|
assert!(
|
||||||
|
all.contains(&metric) && local.contains(&metric),
|
||||||
|
"{metric:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ fn legacy_setting(name: &str, is_set: impl Fn(&str) -> bool) -> Option<String> {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! brand_version {
|
macro_rules! brand_version {
|
||||||
() => {
|
() => {
|
||||||
"2026.9.30.1"
|
"2026.9.30.2"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user