Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions challenge-30/submissions/nzamulov/solution-template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package main

import (
"context"
"fmt"
"time"
)

// ContextManager defines a simplified interface for basic context operations
type ContextManager interface {
// Create a cancellable context from a parent context
CreateCancellableContext(parent context.Context) (context.Context, context.CancelFunc)

// Create a context with timeout
CreateTimeoutContext(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc)

// Add a value to context
AddValue(parent context.Context, key, value interface{}) context.Context

// Get a value from context
GetValue(ctx context.Context, key interface{}) (interface{}, bool)

// Execute a task with context cancellation support
ExecuteWithContext(ctx context.Context, task func() error) error

// Wait for context cancellation or completion
WaitForCompletion(ctx context.Context, duration time.Duration) error
}

// Simple context manager implementation
type simpleContextManager struct{}

// NewContextManager creates a new context manager
func NewContextManager() ContextManager {
return &simpleContextManager{}
}

// CreateCancellableContext creates a cancellable context
func (cm *simpleContextManager) CreateCancellableContext(parent context.Context) (context.Context, context.CancelFunc) {
return context.WithCancel(parent)
}

// CreateTimeoutContext creates a context with timeout
func (cm *simpleContextManager) CreateTimeoutContext(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
return context.WithTimeout(parent, timeout)
}

// AddValue adds a key-value pair to the context
func (cm *simpleContextManager) AddValue(parent context.Context, key, value interface{}) context.Context {
return context.WithValue(parent, key, value)
}

// GetValue retrieves a value from the context
func (cm *simpleContextManager) GetValue(ctx context.Context, key interface{}) (interface{}, bool) {
val := ctx.Value(key)
return val, val != nil
}

// ExecuteWithContext executes a task that can be cancelled via context
func (cm *simpleContextManager) ExecuteWithContext(ctx context.Context, task func() error) error {
ch := make(chan error, 1)

go func() {
ch <- task()
}()

select {
case <-ctx.Done():
return ctx.Err()
case err := <-ch:
return err
}
}

// WaitForCompletion waits for a duration or until context is cancelled
func (cm *simpleContextManager) WaitForCompletion(ctx context.Context, duration time.Duration) error {
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(duration):
return nil
}
}

// Helper function - simulate work that can be cancelled
func SimulateWork(ctx context.Context, workDuration time.Duration, _ string) error {
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(workDuration):
return nil
}
}

// Helper function - process multiple items with context
func ProcessItems(ctx context.Context, items []string) ([]string, error) {
var result []string

ch := make(chan string, 1)

go func() {
defer close(ch)

for _, item := range items {
select {
case <-ctx.Done():
return
default:
}
ch <- fmt.Sprintf("processed_%s", item)
time.Sleep(50 * time.Millisecond)
}
}()

for {
select {
case <-ctx.Done():
return result, ctx.Err()
case item, ok := <-ch:
if !ok {
return result, nil
}
result = append(result, item)
}
}
}
Comment on lines +95 to +126
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Potential goroutine leak in ProcessItems.

There's a race condition between lines 105-110 and the receiver at lines 117-118. If the goroutine passes the ctx.Done() check and attempts to send (line 110) while the receiver simultaneously handles context cancellation and exits, the goroutine may block on the send indefinitely.

Apply this fix to make the send context-aware:

 		for _, item := range items {
 			select {
 			case <-ctx.Done():
 				return
 			default:
 			}
-			ch <- fmt.Sprintf("processed_%s", item)
+			select {
+			case <-ctx.Done():
+				return
+			case ch <- fmt.Sprintf("processed_%s", item):
+			}
 			time.Sleep(50 * time.Millisecond)
 		}

This ensures the goroutine can exit even while attempting to send.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Helper function - process multiple items with context
func ProcessItems(ctx context.Context, items []string) ([]string, error) {
var result []string
ch := make(chan string, 1)
go func() {
defer close(ch)
for _, item := range items {
select {
case <-ctx.Done():
return
default:
}
ch <- fmt.Sprintf("processed_%s", item)
time.Sleep(50 * time.Millisecond)
}
}()
for {
select {
case <-ctx.Done():
return result, ctx.Err()
case item, ok := <-ch:
if !ok {
return result, nil
}
result = append(result, item)
}
}
}
// Helper function - process multiple items with context
func ProcessItems(ctx context.Context, items []string) ([]string, error) {
var result []string
ch := make(chan string, 1)
go func() {
defer close(ch)
for _, item := range items {
select {
case <-ctx.Done():
return
default:
}
select {
case <-ctx.Done():
return
case ch <- fmt.Sprintf("processed_%s", item):
}
time.Sleep(50 * time.Millisecond)
}
}()
for {
select {
case <-ctx.Done():
return result, ctx.Err()
case item, ok := <-ch:
if !ok {
return result, nil
}
result = append(result, item)
}
}
}
🤖 Prompt for AI Agents
In challenge-30/submissions/nzamulov/solution-template.go around lines 95 to
126, the goroutine that sends processed items can block on ch <- ... if the
receiver has already exited due to ctx cancellation; change the send to be
context-aware by replacing the direct send with a select that either sends to
the channel or returns when ctx.Done() is closed (i.e., select { case
<-ctx.Done(): return; case ch <- formattedItem: } ), so the goroutine can always
exit and avoid a leak.


// Example usage
func main() {
fmt.Println("Context Management Challenge")
fmt.Println("Implement the context manager methods!")

// Example of how the context manager should work:
cm := NewContextManager()

// Create a cancellable context
ctx, cancel := cm.CreateCancellableContext(context.Background())
defer cancel()

// Add some values
ctx = cm.AddValue(ctx, "user", "alice")
ctx = cm.AddValue(ctx, "requestID", "12345")

// Use the context
fmt.Println("Context created with values!")
}
Loading