The smokesignal.events web application

refactor: profile links and startup logging

+38 -18
+3 -2
lexicon/events.smokesignal.profile.json
··· 17 17 }, 18 18 "profile_host": { 19 19 "type": "string", 20 - "description": "The service used for profile links", 20 + "description": "The format used for profile links", 21 21 "knownValues": [ 22 22 "bsky.app", 23 - "blacksky.community" 23 + "blacksky.community", 24 + "aturi" 24 25 ] 25 26 }, 26 27 "description": {
+2 -2
src/atproto/lexicon/profile.rs
··· 52 52 if let Some(profile_host) = &self.profile_host 53 53 && profile_host != "bsky.app" 54 54 && profile_host != "blacksky.community" 55 - && profile_host != "smokesignal.events" 55 + && profile_host != "aturi" 56 56 { 57 57 return Err( 58 - "Profile host must be 'bsky.app', 'blacksky.community', or 'smokesignal.events'" 58 + "error-smokesignal-profile-1 Profile host must be 'bsky.app', 'blacksky.community', or 'aturi'" 59 59 .to_string(), 60 60 ); 61 61 }
+7 -3
src/bin/smokesignal.rs
··· 318 318 319 319 if config.enable_jetstream { 320 320 // Try to acquire distributed lock for Jetstream consumer 321 + tracing::info!("Attempting to acquire Jetstream consumer lock..."); 321 322 match DistributedLock::new(cache_pool.clone()).await { 322 323 Ok(mut distributed_lock) => { 323 - // Try to acquire the lock with retry for up to 30 seconds 324 + // Try to acquire the lock with retry for up to 60 seconds 325 + // This is longer than the lock TTL (30s) to ensure any stale locks 326 + // from crashed instances will expire before we give up 324 327 let acquired = match distributed_lock 325 - .acquire_with_retry(std::time::Duration::from_secs(30)) 328 + .acquire_with_retry(std::time::Duration::from_secs(60)) 326 329 .await 327 330 { 328 331 Ok(acquired) => acquired, ··· 334 337 335 338 if !acquired { 336 339 tracing::warn!( 337 - "Could not acquire Jetstream consumer lock - another instance may be running" 340 + "Could not acquire Jetstream consumer lock after 60 seconds - another instance may be running" 338 341 ); 339 342 tracing::info!("This instance will not consume Jetstream events"); 343 + tracing::info!("If no other instance is running, the lock will expire in up to 30 seconds"); 340 344 } else { 341 345 tracing::debug!( 342 346 "Successfully acquired Jetstream consumer lock - starting event consumption"
+1 -1
src/http/handle_settings.rs
··· 723 723 if let Some(ref host) = profile_host 724 724 && host != "bsky.app" 725 725 && host != "blacksky.community" 726 - && host != "smokesignal.events" 726 + && host != "aturi" 727 727 { 728 728 return contextual_error!( 729 729 web_context,
+1 -1
src/http/templates.rs
··· 23 23 match host { 24 24 "bsky.app" => format!("https://bsky.app/profile/{}", did), 25 25 "blacksky.community" => format!("https://blacksky.community/profile/{}", did), 26 - "smokesignal.events" => format!("https://smokesignal.events/{}", did), 26 + "aturi" => format!("at://{}", did), 27 27 _ => format!("https://bsky.app/profile/{}", did), // fallback to bsky.app 28 28 } 29 29 }
+18 -2
src/storage/distributed_lock.rs
··· 52 52 let start = Instant::now(); 53 53 let mut backoff = Duration::from_millis(200); 54 54 let max_backoff = Duration::from_secs(30); 55 + let mut attempt = 0; 55 56 56 57 while start.elapsed() < max_wait { 58 + attempt += 1; 57 59 if self.try_acquire().await? { 58 - tracing::debug!("Successfully acquired Jetstream consumer lock"); 60 + tracing::info!( 61 + "Successfully acquired Jetstream consumer lock after {} attempts in {:?}", 62 + attempt, 63 + start.elapsed() 64 + ); 59 65 return Ok(true); 60 66 } 61 67 68 + // Log periodic updates to show we're still trying 69 + if attempt % 10 == 0 { 70 + tracing::info!( 71 + "Still attempting to acquire lock... (attempt {}, elapsed: {:?})", 72 + attempt, 73 + start.elapsed() 74 + ); 75 + } 76 + 62 77 tokio::time::sleep(backoff).await; 63 78 64 79 // Exponential backoff with jitter ··· 68 83 } 69 84 70 85 tracing::warn!( 71 - "Failed to acquire Jetstream consumer lock after {:?}", 86 + "Failed to acquire Jetstream consumer lock after {} attempts over {:?}", 87 + attempt, 72 88 max_wait 73 89 ); 74 90 Ok(false)
+1 -1
templates/en-us/profile.common.html
··· 28 28 <span class="icon"> 29 29 <i class="fab fa-bluesky"></i> 30 30 </span> 31 - <span>{% if profile_host == "bsky.app" %}Bluesky{% elif profile_host == "blacksky.community" %}Blacksky{% else %}Profile{% endif %}</span> 31 + <span>{% if profile_host == "bsky.app" %}Bluesky{% elif profile_host == "blacksky.community" %}Blacksky{% elif profile_host == "aturi" %}AT-URI{% else %}Profile{% endif %}</span> 32 32 </a> 33 33 34 34 {% if is_self %}
+5 -6
templates/en-us/settings.profile.html
··· 16 16 </div> 17 17 18 18 <div class="field"> 19 - <label class="label">Profile Host</label> 19 + <label class="label">Profile Link Format</label> 20 20 <div class="control"> 21 21 <div class="select is-fullwidth"> 22 22 <select name="profile_host"> 23 - <option value="">None (default)</option> 24 - <option value="bsky.app" {% if profile_host == "bsky.app" %}selected{% endif %}>Bluesky</option> 25 - <option value="blacksky.community" {% if profile_host == "blacksky.community" %}selected{% endif %}>Blacksky Community</option> 26 - <option value="smokesignal.events" {% if profile_host == "smokesignal.events" %}selected{% endif %}>Smokesignal Events</option> 23 + <option value="bsky.app" {% if profile_host == "bsky.app" or not profile_host %}selected{% endif %}>Bluesky (https://bsky.app/profile/{DID})</option> 24 + <option value="blacksky.community" {% if profile_host == "blacksky.community" %}selected{% endif %}>Blacksky (https://blacksky.community/profile/{DID})</option> 25 + <option value="aturi" {% if profile_host == "aturi" %}selected{% endif %}>AT-URI (at://{DID})</option> 27 26 </select> 28 27 </div> 29 28 </div> 30 - <p class="help">Choose where your profile link points</p> 29 + <p class="help">Choose how your profile link is displayed</p> 31 30 </div> 32 31 33 32 <div class="field">