Skip to content

Commit ffb4e90

Browse files
authored
fix: fix deadlock issue in grpc_func and add cors support (#158)
Signed-off-by: Zike Yang <zike@apache.org>
1 parent a95c50a commit ffb4e90

File tree

4 files changed

+72
-37
lines changed

4 files changed

+72
-37
lines changed

fs/instance_impl.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ func (instance *FunctionInstanceImpl) Run(runtimeFactory api.FunctionRuntimeFact
117117
instance.log.ErrorContext(instance.ctx, "Error calling process function", slog.Any("error", err))
118118
return
119119
}
120+
if output == nil {
121+
instance.log.DebugContext(instance.ctx, "output is nil")
122+
continue
123+
}
120124
select {
121125
case sinkChan <- output:
122126
case <-instance.ctx.Done():

fs/runtime/grpc/grpc_func.go

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,17 @@ import (
3333

3434
type GRPCFuncRuntime struct {
3535
api.FunctionRuntime
36-
Name string
37-
instance api.FunctionInstance
38-
ctx context.Context
39-
status *proto.FunctionStatus
40-
readyOnce sync.Once
41-
readyCh chan error
42-
input chan string
43-
output chan string
44-
stopFunc func()
45-
log *slog.Logger
36+
Name string
37+
instance api.FunctionInstance
38+
ctx context.Context
39+
status *proto.FunctionStatus
40+
readyOnce sync.Once
41+
readyCh chan error
42+
input chan contube.Record
43+
output chan contube.Record
44+
stopFunc func()
45+
processing atomic.Bool
46+
log *slog.Logger
4647
}
4748

4849
type Status int32
@@ -155,8 +156,8 @@ func (s *FSSReconcileServer) NewFunctionRuntime(instance api.FunctionInstance) (
155156
Name: name,
156157
instance: instance,
157158
readyCh: make(chan error),
158-
input: make(chan string),
159-
output: make(chan string),
159+
input: make(chan contube.Record),
160+
output: make(chan contube.Record),
160161
status: &proto.FunctionStatus{
161162
Name: name,
162163
Status: proto.FunctionStatus_CREATING,
@@ -227,9 +228,10 @@ func (f *GRPCFuncRuntime) Stop() {
227228
}
228229

229230
func (f *GRPCFuncRuntime) Call(event contube.Record) (contube.Record, error) {
230-
f.input <- string(event.GetPayload())
231+
f.input <- event
231232
out := <-f.output
232-
return contube.NewRecordImpl([]byte(out), event.Commit), nil
233+
f.processing.Store(false)
234+
return out, nil
233235
}
234236

235237
type FunctionServerImpl struct {
@@ -255,12 +257,20 @@ func (f *FunctionServerImpl) Process(req *proto.FunctionProcessRequest, stream p
255257
})
256258
errCh := make(chan error)
257259

260+
defer func() {
261+
if runtime.processing.Load() {
262+
runtime.output <- nil
263+
runtime.processing.Store(false)
264+
}
265+
}()
266+
258267
logCounter := common.LogCounter()
259268
for {
260269
select {
261-
case payload := <-runtime.input:
270+
case event := <-runtime.input:
262271
log.DebugContext(stream.Context(), "sending event", slog.Any("count", logCounter))
263-
err := stream.Send(&proto.Event{Payload: payload})
272+
runtime.processing.Store(true)
273+
err := stream.Send(&proto.Event{Payload: string(event.GetPayload())}) // TODO: Change payload type to bytes
264274
if err != nil {
265275
log.Error("failed to send event", slog.Any("error", err))
266276
return err
@@ -292,7 +302,7 @@ func (f *FunctionServerImpl) Output(ctx context.Context, e *proto.Event) (*proto
292302
return nil, err
293303
}
294304
runtime.log.DebugContext(ctx, "received event")
295-
runtime.output <- e.Payload
305+
runtime.output <- contube.NewRecordImpl([]byte(e.Payload), func() {})
296306
return &proto.Response{
297307
Status: proto.Response_OK,
298308
}, nil

server/server.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type Server struct {
4040
options *serverOptions
4141
httpSvr atomic.Pointer[http.Server]
4242
log *slog.Logger
43-
manager *fs.FunctionManager
43+
Manager *fs.FunctionManager
4444
}
4545

4646
type serverOptions struct {
@@ -59,7 +59,7 @@ func (f serverOptionFunc) apply(c *serverOptions) (*serverOptions, error) {
5959
return f(c)
6060
}
6161

62-
// WithFunctionManager sets the function manager for the server.
62+
// WithFunctionManager sets the function Manager for the server.
6363
func WithFunctionManager(opts ...fs.ManagerOption) ServerOption {
6464
return serverOptionFunc(func(o *serverOptions) (*serverOptions, error) {
6565
o.managerOpts = append(o.managerOpts, opts...)
@@ -114,7 +114,7 @@ func NewServer(opts ...ServerOption) (*Server, error) {
114114
}
115115
return &Server{
116116
options: options,
117-
manager: manager,
117+
Manager: manager,
118118
log: slog.With(),
119119
}, nil
120120
}
@@ -167,8 +167,29 @@ func (s *Server) Run(context context.Context) {
167167
}
168168
}
169169

170+
func corsMiddleware(next http.Handler) http.Handler {
171+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
172+
w.Header().Set("Access-Control-Allow-Origin", "*")
173+
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
174+
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
175+
176+
if r.Method == "OPTIONS" {
177+
w.Header().Set("Access-Control-Max-Age", "86400")
178+
w.WriteHeader(http.StatusOK)
179+
return
180+
}
181+
next.ServeHTTP(w, r)
182+
})
183+
}
184+
170185
func (s *Server) startRESTHandlers() error {
171186
r := mux.NewRouter()
187+
188+
r.PathPrefix("/").Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
189+
})).Methods("OPTIONS")
190+
191+
r.Use(corsMiddleware)
192+
172193
r.HandleFunc("/api/v1/status", func(w http.ResponseWriter, r *http.Request) {
173194
w.WriteHeader(http.StatusOK)
174195
}).Methods("GET")
@@ -208,7 +229,7 @@ func (s *Server) startRESTHandlers() error {
208229
return
209230
}
210231

211-
err = s.manager.StartFunction(f)
232+
err = s.Manager.StartFunction(f)
212233
if err != nil {
213234
log.Error("Failed to start function", "error", err)
214235
http.Error(w, err.Error(), http.StatusBadRequest)
@@ -222,7 +243,7 @@ func (s *Server) startRESTHandlers() error {
222243
functionName := vars["function_name"]
223244
log := s.log.With(slog.String("name", functionName), slog.String("phase", "deleting"))
224245

225-
err := s.manager.DeleteFunction(functionName)
246+
err := s.Manager.DeleteFunction(functionName)
226247
if errors.Is(err, common.ErrorFunctionNotFound) {
227248
log.Error("Function not found", "error", err)
228249
http.Error(w, err.Error(), http.StatusNotFound)
@@ -234,7 +255,7 @@ func (s *Server) startRESTHandlers() error {
234255
r.HandleFunc("/api/v1/functions", func(w http.ResponseWriter, r *http.Request) {
235256
log := s.log.With()
236257
log.Info("Listing functions")
237-
functions := s.manager.ListFunctions()
258+
functions := s.Manager.ListFunctions()
238259
w.Header().Set("Content-Type", "application/json")
239260
err := json.NewEncoder(w).Encode(functions)
240261
if err != nil {
@@ -255,7 +276,7 @@ func (s *Server) startRESTHandlers() error {
255276
http.Error(w, errors.Wrap(err, "Failed to read body").Error(), http.StatusBadRequest)
256277
return
257278
}
258-
err = s.manager.ProduceEvent(queueName, contube.NewRecordImpl(content, func() {}))
279+
err = s.Manager.ProduceEvent(queueName, contube.NewRecordImpl(content, func() {}))
259280
if err != nil {
260281
log.Error("Failed to produce event", "error", err)
261282
http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -269,7 +290,7 @@ func (s *Server) startRESTHandlers() error {
269290
queueName := vars["queue_name"]
270291
log := s.log.With(slog.String("queue_name", queueName))
271292
log.Info("Consuming event from queue")
272-
event, err := s.manager.ConsumeEvent(queueName)
293+
event, err := s.Manager.ConsumeEvent(queueName)
273294
if err != nil {
274295
log.Error("Failed to consume event", "error", err)
275296
http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -304,7 +325,7 @@ func (s *Server) startRESTHandlers() error {
304325
}
305326
log := s.log.With(slog.String("key", key))
306327
log.Info("Getting state")
307-
state := s.manager.GetStateStore()
328+
state := s.Manager.GetStateStore()
308329
if state == nil {
309330
log.Error("No state store configured")
310331
http.Error(w, "No state store configured", http.StatusBadRequest)
@@ -333,7 +354,7 @@ func (s *Server) startRESTHandlers() error {
333354
}
334355
log := s.log.With(slog.String("key", key))
335356
log.Info("Getting state")
336-
state := s.manager.GetStateStore()
357+
state := s.Manager.GetStateStore()
337358
if state == nil {
338359
log.Error("No state store configured")
339360
http.Error(w, "No state store configured", http.StatusBadRequest)
@@ -411,8 +432,8 @@ func (s *Server) Close() error {
411432
return err
412433
}
413434
}
414-
if s.manager != nil {
415-
err := s.manager.Close()
435+
if s.Manager != nil {
436+
err := s.Manager.Close()
416437
if err != nil {
417438
return err
418439
}

server/server_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func TestStandaloneBasicFunction(t *testing.T) {
103103
Name: "test-func",
104104
Replicas: 1,
105105
}
106-
err := s.manager.StartFunction(funcConf)
106+
err := s.Manager.StartFunction(funcConf)
107107
if err != nil {
108108
t.Fatal(err)
109109
}
@@ -116,13 +116,13 @@ func TestStandaloneBasicFunction(t *testing.T) {
116116
if err != nil {
117117
t.Fatal(err)
118118
}
119-
err = s.manager.ProduceEvent(inputTopic, contube.NewRecordImpl(jsonBytes, func() {
119+
err = s.Manager.ProduceEvent(inputTopic, contube.NewRecordImpl(jsonBytes, func() {
120120
}))
121121
if err != nil {
122122
t.Fatal(err)
123123
}
124124

125-
event, err := s.manager.ConsumeEvent(outputTopic)
125+
event, err := s.Manager.ConsumeEvent(outputTopic)
126126
if err != nil {
127127
t.Error(err)
128128
return
@@ -163,7 +163,7 @@ func TestHttpTube(t *testing.T) {
163163
Replicas: 1,
164164
}
165165

166-
err := s.manager.StartFunction(funcConf)
166+
err := s.Manager.StartFunction(funcConf)
167167
assert.Nil(t, err)
168168

169169
p := &tests.Person{
@@ -178,7 +178,7 @@ func TestHttpTube(t *testing.T) {
178178
_, err = http.Post(httpAddr+"/api/v1/http-tube/"+endpoint, "application/json", bytes.NewBuffer(jsonBytes))
179179
assert.Nil(t, err)
180180

181-
event, err := s.manager.ConsumeEvent(funcConf.Output)
181+
event, err := s.Manager.ConsumeEvent(funcConf.Output)
182182
if err != nil {
183183
t.Error(err)
184184
return
@@ -243,19 +243,19 @@ func TestStatefulFunction(t *testing.T) {
243243
Output: "output",
244244
Replicas: 1,
245245
}
246-
err := s.manager.StartFunction(funcConf)
246+
err := s.Manager.StartFunction(funcConf)
247247
if err != nil {
248248
t.Fatal(err)
249249
}
250250

251251
_, err = http.Post(httpAddr+"/api/v1/state/key", "text/plain; charset=utf-8", bytes.NewBuffer([]byte("hello")))
252252
assert.Nil(t, err)
253253

254-
err = s.manager.ProduceEvent(funcConf.Inputs[0], contube.NewRecordImpl(nil, func() {
254+
err = s.Manager.ProduceEvent(funcConf.Inputs[0], contube.NewRecordImpl(nil, func() {
255255
}))
256256
assert.Nil(t, err)
257257

258-
_, err = s.manager.ConsumeEvent(funcConf.Output)
258+
_, err = s.Manager.ConsumeEvent(funcConf.Output)
259259
assert.Nil(t, err)
260260

261261
resp, err := http.Get(httpAddr + "/api/v1/state/key")

0 commit comments

Comments
 (0)