
[英]Why do I not get a deadlock when trying to read from a channel that never receives data in a goroutine but do in the main func
[英]Why are my opentelemetry events printing when ranging over a channel, but not events from the main goroutine
我很困惑为什么我的事件只在一个通道内的循环内打印,而不是来自主 goroutine 的那些。 看来我只能做
我有一种感觉我错误地使用了上下文
希望我能够做到:
最终:
这是我的完整代码:
import (
"context"
"encoding/json"
"fmt"
"log"
"math/rand"
"os"
"path/filepath"
"runtime"
"sync"
"time"
"github.com/nats-io/nats.go"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace"
)
var (
natsURL = "localhost:4222"
subject = "listen.to.refresher"
sub *nats.Subscription
)
type NewRequest struct {
Requestid string `json: "requestid"`
}
func main() {
ctx := context.Background()
execName, _ := os.Executable()
stdoutExporter, err := stdout.New(stdout.WithPrettyPrint())
if err != nil {
log.Fatal(err)
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(stdoutExporter),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(filepath.Base(execName)),
semconv.ServiceVersionKey.String("v1.0.0"),
attribute.String("environment", "dev"),
)),
)
defer func() { _ = tp.Shutdown(ctx) }()
otel.SetTracerProvider(tp) // sets globally. I believe this is correct
otel.SetTextMapPropagator(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
),
)
var mainSpan trace.Span
ctx, mainSpan = otel.Tracer("main").Start(ctx, "mainSpan") // should I initialise the tracer with no name?
defer mainSpan.End()
mainSpan.AddEvent("WHY DOESN'T THIS PRINT?") //HERE!!!!!!
nc, err := nats.Connect(natsURL)
if err != nil {
log.Fatal(err)
}
requests := make(chan NewRequest)
var wg sync.WaitGroup
_, err = nc.QueueSubscribe(subject, subject, func(msg *nats.Msg) { // here is where requests come in. This is a go routine waiting on inbound nats messages to come in, before adding them to a channel
wg.Add(1)
nr := new(NewRequest)
err := json.Unmarshal(msg.Data, &nr)
if err != nil {
mainSpan.RecordError(err)
mainSpan.SetStatus(codes.Error, err.Error())
log.Fatal(err)
}
response := fmt.Sprintf("response from the subscriber! requestid: %s", nr.Requestid)
msg.Respond([]byte(response))
requests <- *nr
})
if err != nil {
mainSpan.RecordError(err)
mainSpan.SetStatus(codes.Error, err.Error())
}
for request := range requests { // processing each request in the channel
tracer := otel.GetTracerProvider().Tracer("requests")
requesterSpan := trace.SpanFromContext(ctx)
requestCtx := trace.ContextWithSpan(ctx, requesterSpan)
var requestInLoopSpan trace.Span
requestCtxChild, requestInLoopSpan := tracer.Start(requestCtx, "requestInLoopSpan")
requestInLoopSpan.AddEvent("processing....") // THIS PRINTS TO STDOUT
go func(requestCtxChild context.Context, request NewRequest) {
mainCtx2, _ = callDatabase2(requestCtxChild, request)
defer requestInLoopSpan.End()
defer wg.Done()
}(requestCtxChild, request)
requestCtxChild.Done()
}
wg.Wait()
runtime.Goexit()
}
func callDatabase2(ctx context.Context, request NewRequest) (context.Context, string) {
minTime := 1.0
maxTime := 2.0
var callDatabase2Span trace.Span
ctx, callDatabase2Span = otel.Tracer("").Start(ctx, "callDatabase2")
defer callDatabase2Span.End()
time.Sleep(time.Second * (time.Duration(minTime + rand.Float64()*(maxTime-minTime)))) // simulate db doing something
callDatabase2Span.AddEvent("finished!") // THIS DOES PRINT TO STDOUT
return ctx, request.Requestid
}`
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.