go.uber.org/cadence@v1.2.9/internal/context.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package internal 22 23 import ( 24 "fmt" 25 "sync" 26 "time" 27 28 "github.com/opentracing/opentracing-go" 29 30 "go.uber.org/cadence/.gen/go/shared" 31 ) 32 33 const activeSpanContextKey contextKey = "activeSpanContextKey" 34 35 // Context is a clone of context.Context with Done() returning Channel instead 36 // of native channel. 37 // A Context carries a deadline, a cancellation signal, and other values across 38 // API boundaries. 39 // 40 // Context's methods may be called by multiple goroutines simultaneously. 41 type Context interface { 42 // Deadline returns the time when work done on behalf of this context 43 // should be canceled. Deadline returns ok==false when no deadline is 44 // set. Successive calls to Deadline return the same results. 45 Deadline() (deadline time.Time, ok bool) 46 47 // Done returns a channel that's closed when work done on behalf of this 48 // context should be canceled. Done may return nil if this context can 49 // never be canceled. Successive calls to Done return the same value. 50 // 51 // WithCancel arranges for Done to be closed when cancel is called; 52 // WithDeadline arranges for Done to be closed when the deadline 53 // expires; WithTimeout arranges for Done to be closed when the timeout 54 // elapses. 55 // 56 // Done is provided for use in select statements: 57 // 58 // // Stream generates values with DoSomething and sends them to out 59 // // until DoSomething returns an error or ctx.Done is closed. 60 // func Stream(ctx Context, out Channel) (err error) { 61 // for { 62 // v, err := DoSomething(ctx) 63 // if err != nil { 64 // return err 65 // } 66 // s := NewSelector(ctx) 67 // s.AddReceive(ctx.Done(), func(v interface{}) { err = ctx.Err() }) 68 // s.AddReceive(v, func(v interface{}, more bool) { out.Send(ctx, v) }) 69 // s.Select(ctx) 70 // if err != nil { 71 // return err 72 // } 73 // } 74 // } 75 // 76 // See http://blog.golang.org/pipelines for more examples of how to use 77 // a Done channel for cancellation. 78 Done() Channel 79 80 // Err returns a non-nil error value after Done is closed. Err returns 81 // Canceled if the context was canceled or DeadlineExceeded if the 82 // context's deadline passed. No other values for Err are defined. 83 // After Done is closed, successive calls to Err return the same value. 84 Err() error 85 86 // Value returns the value associated with this context for key, or nil 87 // if no value is associated with key. Successive calls to Value with 88 // the same key returns the same result. 89 // 90 // Use context values only for request-scoped data that transits 91 // processes and API boundaries, not for passing optional parameters to 92 // functions. 93 // 94 // A key identifies a specific value in a Context. Functions that wish 95 // to store values in Context typically allocate a key in a global 96 // variable then use that key as the argument to context.WithValue and 97 // Context.Value. A key can be any type that supports equality; 98 // packages should define keys as an unexported type to avoid 99 // collisions. 100 // 101 // Packages that define a Context key should provide type-safe accessors 102 // for the values stores using that key: 103 // 104 // // Package user defines a User type that's stored in Contexts. 105 // package user 106 // 107 // import "golang.org/x/net/context" 108 // 109 // // User is the type of value stored in the Contexts. 110 // type User struct {...} 111 // 112 // // key is an unexported type for keys defined in this package. 113 // // This prevents collisions with keys defined in other packages. 114 // type key int 115 // 116 // // userKey is the key for user.User values in Contexts. It is 117 // // unexported; clients use user.NewContext and user.FromContext 118 // // instead of using this key directly. 119 // var userKey key = 0 120 // 121 // // NewContext returns a new Context that carries value u. 122 // func NewContext(ctx context.Context, u *User) context.Context { 123 // return context.WithValue(ctx, userKey, u) 124 // } 125 // 126 // // FromContext returns the User value stored in ctx, if any. 127 // func FromContext(ctx context.Context) (*User, bool) { 128 // u, ok := ctx.Value(userKey).(*User) 129 // return u, ok 130 // } 131 Value(key interface{}) interface{} 132 } 133 134 // An emptyCtx is never canceled, has no values, and has no deadline. It is not 135 // struct{}, since vars of this type must have distinct addresses. 136 type emptyCtx int 137 138 func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { 139 return 140 } 141 142 func (*emptyCtx) Done() Channel { 143 return nil 144 } 145 146 func (*emptyCtx) Err() error { 147 return nil 148 } 149 150 func (*emptyCtx) Value(key interface{}) interface{} { 151 return nil 152 } 153 154 func (e *emptyCtx) String() string { 155 switch e { 156 case background: 157 return "context.Background" 158 case todo: 159 return "context.TODO" 160 } 161 return "unknown empty Context" 162 } 163 164 var ( 165 background = new(emptyCtx) 166 todo = new(emptyCtx) 167 ) 168 169 // Background returns a non-nil, empty Context. It is never canceled, has no 170 // values, and has no deadline 171 func Background() Context { 172 return background 173 } 174 175 // ErrCanceled is the error returned by Context.Err when the context is canceled. 176 var ErrCanceled = NewCanceledError() 177 178 // ErrDeadlineExceeded is the error returned by Context.Err when the context's 179 // deadline passes. 180 var ErrDeadlineExceeded = NewTimeoutError(shared.TimeoutTypeScheduleToClose) 181 182 // A CancelFunc tells an operation to abandon its work. 183 // A CancelFunc does not wait for the work to stop. 184 // After the first call, subsequent calls to a CancelFunc do nothing. 185 type CancelFunc func() 186 187 // WithCancel returns a copy of parent with a new Done channel. The returned 188 // context's Done channel is closed when the returned cancel function is called 189 // or when the parent context's Done channel is closed, whichever happens first. 190 // 191 // Canceling this context releases resources associated with it, so code should 192 // call cancel as soon as the operations running in this Context complete. 193 func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { 194 c := newCancelCtx(parent) 195 propagateCancel(parent, c) 196 return c, func() { c.cancel(true, ErrCanceled) } 197 } 198 199 // NewDisconnectedContext returns a new context that won't propagate parent's cancellation to the new child context. 200 // One common use case is to do cleanup work after workflow is cancelled. 201 // 202 // err := workflow.ExecuteActivity(ctx, ActivityFoo).Get(ctx, &activityFooResult) 203 // if err != nil && cadence.IsCanceledError(ctx.Err()) { 204 // // activity failed, and workflow context is canceled 205 // disconnectedCtx, _ := workflow.newDisconnectedContext(ctx); 206 // workflow.ExecuteActivity(disconnectedCtx, handleCancellationActivity).Get(disconnectedCtx, nil) 207 // return err // workflow return CanceledError 208 // } 209 func NewDisconnectedContext(parent Context) (ctx Context, cancel CancelFunc) { 210 c := newCancelCtx(parent) 211 return c, func() { c.cancel(true, ErrCanceled) } 212 } 213 214 // newCancelCtx returns an initialized cancelCtx. 215 func newCancelCtx(parent Context) *cancelCtx { 216 return &cancelCtx{ 217 Context: parent, 218 done: NewNamedChannel(parent, "cancelCtx-done-channel"), 219 } 220 } 221 222 // propagateCancel arranges for child to be canceled when parent is. 223 func propagateCancel(parent Context, child canceler) { 224 if parent.Done() == nil { 225 return // parent is never canceled 226 } 227 if p, ok := parentCancelCtx(parent); ok { 228 p.cancelLock.Lock() 229 if p.err != nil { 230 p.cancelLock.Unlock() 231 // parent has already been canceled 232 child.cancel(false, p.err) 233 } else { 234 p.childrenLock.Lock() 235 p.children = append(p.children, child) 236 p.childrenLock.Unlock() 237 p.cancelLock.Unlock() 238 } 239 } else { 240 go func() { 241 s := NewSelector(parent) 242 s.AddReceive(parent.Done(), func(c Channel, more bool) { 243 child.cancel(false, parent.Err()) 244 }) 245 s.AddReceive(child.Done(), func(c Channel, more bool) {}) 246 s.Select(parent) 247 }() 248 } 249 } 250 251 // parentCancelCtx follows a chain of parent references until it finds a 252 // *cancelCtx. This function understands how each of the concrete types in this 253 // package represents its parent. 254 func parentCancelCtx(parent Context) (*cancelCtx, bool) { 255 for { 256 switch c := parent.(type) { 257 case *cancelCtx: 258 return c, true 259 // TODO: Uncomment once timer story is implemented 260 // case *timerCtx: 261 // return c.cancelCtx, true 262 case *valueCtx: 263 parent = c.Context 264 default: 265 return nil, false 266 } 267 } 268 } 269 270 // removeChild removes a context from its parent. 271 func removeChild(parent Context, child canceler) { 272 p, ok := parentCancelCtx(parent) 273 if !ok { 274 return 275 } 276 277 p.childrenLock.Lock() 278 defer p.childrenLock.Unlock() 279 if p.children != nil { 280 removeChildFromSlice(p.children, child) 281 } 282 } 283 284 // Helper to remove a child from a context's canceler list. 285 // There should only ever be one instance per list due to code elsewhere, 286 // but this func does not check or enforce that. 287 func removeChildFromSlice(children []canceler, child canceler) []canceler { 288 // This maintains the original order, mostly because it makes behavior easier to reason about 289 // in case that becomes necessary (e.g. bug hunting). 290 // Out-of-order (move last item into the gap) is equally correct and slightly more efficient, 291 // but this likely cannot be changed without changing the order of code execution. 292 found := -1 293 for idx, c := range children { 294 if c == child { 295 found = idx 296 break 297 } 298 } 299 if found >= 0 { 300 children = append(children[:found], children[found+1:]...) 301 } 302 return children 303 } 304 305 // A canceler is a context type that can be canceled directly. The 306 // implementations are *cancelCtx and *timerCtx. 307 type canceler interface { 308 cancel(removeFromParent bool, err error) 309 Done() Channel 310 } 311 312 // A cancelCtx can be canceled. When canceled, it also cancels any children 313 // that implement canceler. 314 type cancelCtx struct { 315 Context 316 317 done Channel // closed by the first cancel call. 318 319 cancelLock sync.Mutex 320 canceled bool 321 322 childrenLock sync.Mutex 323 children []canceler 324 err error // set to non-nil by the first cancel call 325 } 326 327 func (c *cancelCtx) Done() Channel { 328 return c.done 329 } 330 331 func (c *cancelCtx) Err() error { 332 return c.err 333 } 334 335 func (c *cancelCtx) String() string { 336 return fmt.Sprintf("%v.WithCancel", c.Context) 337 } 338 339 func (c *cancelCtx) getChildren() []canceler { 340 c.childrenLock.Lock() 341 defer c.childrenLock.Unlock() 342 343 dup := make([]canceler, len(c.children)) 344 copy(dup, c.children) 345 return dup 346 } 347 348 // cancel closes c.done, cancels each of c's children, and, if 349 // removeFromParent is true, removes c from its parent's children. 350 func (c *cancelCtx) cancel(removeFromParent bool, err error) { 351 c.cancelLock.Lock() 352 if c.canceled { 353 c.cancelLock.Unlock() 354 // calling cancel from multiple go routines isn't safe 355 // avoid a data race by only allowing the first call 356 return 357 } 358 c.canceled = true 359 360 if err == nil { 361 panic("context: internal error: missing cancel error") 362 } 363 if c.err != nil { 364 c.cancelLock.Unlock() 365 return // already canceled 366 } 367 c.err = err 368 c.cancelLock.Unlock() 369 c.done.Close() 370 371 children := c.getChildren() 372 for _, child := range children { 373 // NOTE: acquiring the child's lock while holding parent's lock. 374 child.cancel(false, err) 375 } 376 c.childrenLock.Lock() 377 c.children = nil 378 c.childrenLock.Unlock() 379 380 if removeFromParent { 381 removeChild(c.Context, c) 382 } 383 } 384 385 // Commented out until workflow time API is exposed. 386 // WithDeadline returns a copy of the parent context with the deadline adjusted 387 // to be no later than d. If the parent's deadline is already earlier than d, 388 // WithDeadline(parent, d) is semantically equivalent to parent. The returned 389 // context's Done channel is closed when the deadline expires, when the returned 390 // cancel function is called, or when the parent context's Done channel is 391 // closed, whichever happens first. 392 // 393 // Canceling this context releases resources associated with it, so code should 394 // call cancel as soon as the operations running in this Context complete. 395 // func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { 396 // if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { 397 // // The current deadline is already sooner than the new one. 398 // return WithCancel(parent) 399 // } 400 // c := &timerCtx{ 401 // cancelCtx: newCancelCtx(parent), 402 // deadline: deadline, 403 // } 404 // propagateCancel(parent, c) 405 // d := deadline.Sub(time.Now()) 406 // if d <= 0 { 407 // c.cancel(true, DeadlineExceeded) // deadline has already passed 408 // return c, func() { c.cancel(true, Canceled) } 409 // } 410 // if c.err == nil { 411 // c.timer = time.AfterFunc(d, func() { 412 // c.cancel(true, DeadlineExceeded) 413 // }) 414 // } 415 // return c, func() { c.cancel(true, Canceled) } 416 // } 417 // 418 // // A timerCtx carries a timer and a deadline. It embeds a cancelCtx to 419 // // implement Done and Err. It implements cancel by stopping its timer then 420 // // delegating to cancelCtx.cancel. 421 // type timerCtx struct { 422 // *cancelCtx 423 // timer *time.Timer // Under cancelCtx.mu. 424 // 425 // deadline time.Time 426 // } 427 // 428 // func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { 429 // return c.deadline, true 430 // } 431 // 432 // func (c *timerCtx) String() string { 433 // return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) 434 // } 435 // 436 // func (c *timerCtx) cancel(removeFromParent bool, err error) { 437 // c.cancelCtx.cancel(false, err) 438 // if removeFromParent { 439 // // Remove this timerCtx from its parent cancelCtx's children. 440 // removeChild(c.cancelCtx.Context, c) 441 // } 442 // if c.timer != nil { 443 // c.timer.Stop() 444 // c.timer = nil 445 // } 446 // } 447 // 448 // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). 449 // 450 // Canceling this context releases resources associated with it, so code should 451 // call cancel as soon as the operations running in this Context complete: 452 // 453 // func slowOperationWithTimeout(ctx context.Context) (Result, error) { 454 // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) 455 // defer cancel() // releases resources if slowOperation completes before timeout elapses 456 // return slowOperation(ctx) 457 // } 458 // func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { 459 // return WithDeadline(parent, time.Now().Add(timeout)) 460 // } 461 462 // WithValue returns a copy of parent in which the value associated with key is 463 // val. 464 // 465 // Use context Values only for request-scoped data that transits processes and 466 // APIs, not for passing optional parameters to functions. 467 func WithValue(parent Context, key interface{}, val interface{}) Context { 468 return &valueCtx{parent, key, val} 469 } 470 471 // A valueCtx carries a key-value pair. It implements Value for that key and 472 // delegates all other calls to the embedded Context. 473 type valueCtx struct { 474 Context 475 key, val interface{} 476 } 477 478 func (c *valueCtx) String() string { 479 return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) 480 } 481 482 func (c *valueCtx) Value(key interface{}) interface{} { 483 if c.key == key { 484 return c.val 485 } 486 return c.Context.Value(key) 487 } 488 489 func spanFromContext(ctx Context) opentracing.SpanContext { 490 val := ctx.Value(activeSpanContextKey) 491 if sp, ok := val.(opentracing.SpanContext); ok { 492 return sp 493 } 494 return nil 495 } 496 497 func contextWithSpan(ctx Context, spanContext opentracing.SpanContext) Context { 498 return WithValue(ctx, activeSpanContextKey, spanContext) 499 }