Skip to content

Commit af074db

Browse files
committed
cache tool producers
1 parent 29e22d8 commit af074db

File tree

3 files changed

+53
-10
lines changed

3 files changed

+53
-10
lines changed

pkg/pftools/invocation.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type FunctionInvoker struct {
3737
client pulsar.Client
3838
resultChannels map[string]chan FunctionResult
3939
mutex sync.RWMutex
40+
manager *PulsarFunctionManager
4041
}
4142

4243
// FunctionResult represents the result of a function invocation
@@ -46,11 +47,12 @@ type FunctionResult struct {
4647
}
4748

4849
// NewFunctionInvoker creates a new FunctionInvoker
49-
func NewFunctionInvoker(client pulsar.Client) *FunctionInvoker {
50+
func NewFunctionInvoker(manager *PulsarFunctionManager) *FunctionInvoker {
5051
return &FunctionInvoker{
51-
client: client,
52+
client: manager.pulsarClient,
5253
resultChannels: make(map[string]chan FunctionResult),
5354
mutex: sync.RWMutex{},
55+
manager: manager,
5456
}
5557
}
5658

@@ -164,13 +166,10 @@ func (fi *FunctionInvoker) setupConsumer(ctx context.Context, inputTopic, output
164166

165167
// sendMessage sends a message to the input topic
166168
func (fi *FunctionInvoker) sendMessage(ctx context.Context, inputTopic string, payload []byte) (string, error) {
167-
producer, err := fi.client.CreateProducer(pulsar.ProducerOptions{
168-
Topic: inputTopic,
169-
})
169+
producer, err := fi.manager.GetProducer(inputTopic)
170170
if err != nil {
171-
return "", fmt.Errorf("failed to create producer: %w", err)
171+
return "", fmt.Errorf("failed to get producer for topic %s: %w", inputTopic, err)
172172
}
173-
defer producer.Close()
174173

175174
// Send the message with properties
176175
msgID, err := producer.Send(ctx, &pulsar.ProducerMessage{

pkg/pftools/manager.go

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"sync"
2727
"time"
2828

29+
"github.com/apache/pulsar-client-go/pulsar"
2930
"github.com/apache/pulsar-client-go/pulsaradmin/pkg/admin/config"
3031
"github.com/apache/pulsar-client-go/pulsaradmin/pkg/rest"
3132
"github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils"
@@ -34,7 +35,7 @@ import (
3435
"github.com/mark3labs/mcp-go/mcp"
3536
"github.com/mark3labs/mcp-go/server"
3637
"github.com/streamnative/pulsarctl/pkg/cmdutils"
37-
"github.com/streamnative/streamnative-mcp-server/pkg/pulsar"
38+
pulsarutils "github.com/streamnative/streamnative-mcp-server/pkg/pulsar"
3839
"github.com/streamnative/streamnative-mcp-server/pkg/schema"
3940
)
4041

@@ -56,7 +57,7 @@ var DefaultStringSchemaInfo = &SchemaInfo{
5657
// NewPulsarFunctionManager creates a new PulsarFunctionManager
5758
func NewPulsarFunctionManager(mcpServer *server.MCPServer, readOnly bool, options *ManagerOptions) (*PulsarFunctionManager, error) {
5859
// Get Pulsar client and admin client
59-
pulsarClient, err := pulsar.GetPulsarClient()
60+
pulsarClient, err := pulsarutils.GetPulsarClient()
6061
if err != nil {
6162
return nil, fmt.Errorf("failed to get Pulsar client: %w", err)
6263
}
@@ -74,6 +75,8 @@ func NewPulsarFunctionManager(mcpServer *server.MCPServer, readOnly bool, option
7475
pulsarClient: pulsarClient,
7576
fnToToolMap: make(map[string]*FunctionTool),
7677
mutex: sync.RWMutex{},
78+
producerCache: make(map[string]pulsar.Producer),
79+
producerMutex: sync.RWMutex{},
7780
pollInterval: options.PollInterval,
7881
stopCh: make(chan struct{}),
7982
callInProgressMap: make(map[string]context.CancelFunc),
@@ -96,6 +99,15 @@ func (m *PulsarFunctionManager) Start() {
9699
// Stop stops polling for functions
97100
func (m *PulsarFunctionManager) Stop() {
98101
close(m.stopCh)
102+
103+
m.producerMutex.Lock()
104+
defer m.producerMutex.Unlock()
105+
for topic, producer := range m.producerCache {
106+
log.Printf("Closing producer for topic: %s", topic)
107+
producer.Close()
108+
}
109+
m.producerCache = make(map[string]pulsar.Producer)
110+
log.Println("All cached producers closed and cache cleared.")
99111
}
100112

101113
// pollFunctions polls for functions periodically
@@ -406,7 +418,7 @@ func (m *PulsarFunctionManager) handleToolCall(fnTool *FunctionTool) func(ctx co
406418
}
407419

408420
// Create function invoker
409-
invoker := NewFunctionInvoker(m.pulsarClient)
421+
invoker := NewFunctionInvoker(m)
410422

411423
// Create context with timeout
412424
timeoutCtx, cancel := context.WithTimeout(ctx, m.defaultTimeout)
@@ -484,3 +496,33 @@ func retrieveToolDescription(fn *utils.FunctionConfig) string {
484496
}
485497
return fallbackDescription
486498
}
499+
500+
// GetProducer retrieves a producer from the cache or creates a new one if not found.
501+
func (m *PulsarFunctionManager) GetProducer(topic string) (pulsar.Producer, error) {
502+
m.producerMutex.RLock()
503+
producer, found := m.producerCache[topic]
504+
m.producerMutex.RUnlock()
505+
506+
if found {
507+
return producer, nil
508+
}
509+
510+
m.producerMutex.Lock()
511+
defer m.producerMutex.Unlock()
512+
513+
producer, found = m.producerCache[topic]
514+
if found {
515+
return producer, nil
516+
}
517+
518+
newProducer, err := m.pulsarClient.CreateProducer(pulsar.ProducerOptions{
519+
Topic: topic,
520+
})
521+
if err != nil {
522+
return nil, fmt.Errorf("failed to create producer for topic %s: %w", topic, err)
523+
}
524+
525+
m.producerCache[topic] = newProducer
526+
log.Printf("Created and cached producer for topic: %s", topic)
527+
return newProducer, nil
528+
}

pkg/pftools/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ type PulsarFunctionManager struct {
3636
pulsarClient pulsar.Client
3737
fnToToolMap map[string]*FunctionTool
3838
mutex sync.RWMutex
39+
producerCache map[string]pulsar.Producer
40+
producerMutex sync.RWMutex
3941
pollInterval time.Duration
4042
stopCh chan struct{}
4143
callInProgressMap map[string]context.CancelFunc

0 commit comments

Comments
 (0)