···290290 }
291291 }
292292293293+ // Create a root span so all backfill PDS calls are grouped under one trace
294294+ backfillCtx, backfillSpan := tracing.HandlerSpan(ctx, "backfill.startup")
295295+293296 // Backfill all collected DIDs
294297 successCount := 0
295298 for did := range didsToBackfill {
296296- if err := firehoseConsumer.BackfillDID(ctx, did); err != nil {
299299+ if err := firehoseConsumer.BackfillDID(backfillCtx, did); err != nil {
297300 log.Warn().Err(err).Str("did", did).Msg("Failed to backfill user")
298301 } else {
299302 successCount++
300303 }
301304 }
305305+ backfillSpan.End()
302306 log.Info().Int("total", len(didsToBackfill)).Int("success", successCount).Msg("Backfill complete")
303307 }()
304308···306310 // This ensures users are added to the feed even if they had an existing session
307311 oauthManager.SetOnAuthSuccess(func(did string) {
308312 feedRegistry.Register(did)
309309- // Backfill the user's records
313313+ // Backfill the user's records (BackfillUser creates its own span
314314+ // only when there is actual work to do, avoiding empty traces for
315315+ // already-backfilled users)
310316 go func() {
311317 if err := firehoseConsumer.BackfillDID(context.Background(), did); err != nil {
312318 log.Warn().Err(err).Str("did", did).Msg("Failed to backfill new user")
+17
internal/atproto/public_client.go
···1313 "sync"
1414 "time"
15151616+ "arabica/internal/tracing"
1717+1618 "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
1719)
1820···118120 return pds, nil
119121 }
120122 c.pdsCacheMu.RUnlock()
123123+124124+ ctx, span := tracing.PdsSpan(ctx, "resolvePDS", "did:plc", did)
125125+ defer span.End()
121126122127 // Resolve DID document from PLC directory
123128 var pdsEndpoint string
···217222218223// GetProfile fetches a user's public profile by DID or handle
219224func (c *PublicClient) GetProfile(ctx context.Context, actor string) (*Profile, error) {
225225+ ctx, span := tracing.PdsSpan(ctx, "getProfile", "app.bsky.actor", actor)
226226+ defer span.End()
227227+220228 reqURL := fmt.Sprintf("%s/xrpc/app.bsky.actor.getProfile?actor=%s",
221229 c.baseURL, url.QueryEscape(actor))
222230···247255// Records are returned in reverse chronological order (newest first)
248256// This queries the user's PDS directly to support custom collections
249257func (c *PublicClient) ListRecords(ctx context.Context, did, collection string, limit int) (*PublicListRecordsOutput, error) {
258258+ ctx, span := tracing.PdsSpan(ctx, "publicListRecords", collection, did)
259259+ defer span.End()
260260+250261 // Resolve the user's PDS endpoint
251262 pdsEndpoint, err := c.GetPDSEndpoint(ctx, did)
252263 if err != nil {
···281292282293// ResolveHandle resolves an AT Protocol handle to a DID
283294func (c *PublicClient) ResolveHandle(ctx context.Context, handle string) (string, error) {
295295+ ctx, span := tracing.PdsSpan(ctx, "resolveHandle", "com.atproto.identity", handle)
296296+ defer span.End()
297297+284298 reqURL := fmt.Sprintf("%s/xrpc/com.atproto.identity.resolveHandle?handle=%s",
285299 c.baseURL, url.QueryEscape(handle))
286300···315329316330// GetRecord fetches a single public record from the user's PDS
317331func (c *PublicClient) GetRecord(ctx context.Context, did, collection, rkey string) (*PublicRecordEntry, error) {
332332+ ctx, span := tracing.PdsSpan(ctx, "publicGetRecord", collection, did)
333333+ defer span.End()
334334+318335 // Resolve the user's PDS endpoint
319336 pdsEndpoint, err := c.GetPDSEndpoint(ctx, did)
320337 if err != nil {