@@ -37,12 +37,16 @@ import (
3737 queueMySQL "github.com/uber/submitqueue/platform/extension/messagequeue/mysql"
3838 "github.com/uber/submitqueue/service/stovepipe/server/mapper"
3939 "github.com/uber/submitqueue/stovepipe/controller"
40+ "github.com/uber/submitqueue/stovepipe/controller/build"
4041 "github.com/uber/submitqueue/stovepipe/controller/dlq"
4142 "github.com/uber/submitqueue/stovepipe/controller/process"
4243 stovepipemq "github.com/uber/submitqueue/stovepipe/core/messagequeue"
44+ "github.com/uber/submitqueue/stovepipe/extension/buildrunner"
45+ buildrunnerfake "github.com/uber/submitqueue/stovepipe/extension/buildrunner/fake"
4346 queueconfigdefault "github.com/uber/submitqueue/stovepipe/extension/queueconfig/default"
4447 "github.com/uber/submitqueue/stovepipe/extension/sourcecontrol"
4548 sourcecontrolfake "github.com/uber/submitqueue/stovepipe/extension/sourcecontrol/fake"
49+ "github.com/uber/submitqueue/stovepipe/extension/storage"
4650 storageMySQL "github.com/uber/submitqueue/stovepipe/extension/storage/mysql"
4751 "go.uber.org/zap"
4852 "google.golang.org/grpc"
@@ -100,6 +104,15 @@ func (fakeSourceControlFactory) For(cfg sourcecontrol.Config) (sourcecontrol.Sou
100104 return sourcecontrolfake .New ([]string {fmt .Sprintf ("git://%s/HEAD" , cfg .QueueName )}), nil
101105}
102106
107+ // fakeBuildRunnerFactory is the example BuildRunner factory: every queue shares the same
108+ // stateless fake runner, which succeeds unless a caller embeds a failure marker in the head
109+ // URI. A real deployment supplies a backend-specific factory (e.g. Buildkite, per queue).
110+ type fakeBuildRunnerFactory struct {}
111+
112+ func (fakeBuildRunnerFactory ) For (_ buildrunner.Config ) (buildrunner.BuildRunner , error ) {
113+ return buildrunnerfake .New (), nil
114+ }
115+
103116func main () {
104117 code := 0
105118 if err := run (); err != nil {
@@ -225,24 +238,21 @@ func run() error {
225238 errs .AlwaysRetryableProcessor ,
226239 )
227240
228- processController := process .NewController (
229- logger .Sugar (),
230- scope ,
231- store ,
232- queueconfigdefault .NewStore (),
233- fakeSourceControlFactory {},
234- registry ,
235- stovepipemq .TopicKeyProcess ,
236- "stovepipe-process" ,
237- )
238- if err := primaryConsumer .Register (processController ); err != nil {
239- return fmt .Errorf ("failed to register process controller: %w" , err )
240- }
241+ // Each factory is constructed once and threaded through every consumer of
242+ // it, so a real (stateful) backend introduced later is shared rather than
243+ // silently duplicated across controllers.
244+ scf := fakeSourceControlFactory {}
245+ brf := fakeBuildRunnerFactory {}
241246
242- processDLQController := dlq . NewController ( logger .Sugar (), scope , store , dlq . TopicKey ( stovepipemq . TopicKeyProcess ), "stovepipe-process-dlq" )
243- if err := dlqConsumer . Register ( processDLQController ); err != nil {
244- return fmt . Errorf ( "failed to register process dlq controller: %w" , err )
247+ primaryCount , err := registerPrimaryControllers ( primaryConsumer , logger .Sugar (), scope , store , registry , scf , brf )
248+ if err != nil {
249+ return err
245250 }
251+ dlqCount , err := registerDLQControllers (dlqConsumer , logger .Sugar (), scope , store , registry )
252+ if err != nil {
253+ return err
254+ }
255+ logger .Info ("controllers registered" , zap .Int ("primary" , primaryCount ), zap .Int ("dlq" , dlqCount ))
246256
247257 // Start consumers. DLQ first because Start begins processing messages
248258 // immediately; if the primary consumer then fails to start, the half we
@@ -266,7 +276,7 @@ func run() error {
266276 logger .Sugar (),
267277 scope ,
268278 newInMemoryCounter (),
269- fakeSourceControlFactory {} ,
279+ scf ,
270280 store ,
271281 registry ,
272282 )
@@ -338,10 +348,67 @@ func run() error {
338348 return err
339349}
340350
351+ // registerPrimaryControllers creates the primary-pipeline queue controllers and
352+ // registers them with c, returning how many were registered.
353+ func registerPrimaryControllers (
354+ c consumer.Consumer ,
355+ logger * zap.SugaredLogger ,
356+ scope tally.Scope ,
357+ store storage.Storage ,
358+ registry consumer.TopicRegistry ,
359+ scf sourcecontrol.Factory ,
360+ brf buildrunner.Factory ,
361+ ) (int , error ) {
362+ var count int
363+
364+ processController := process .NewController (
365+ logger ,
366+ scope ,
367+ store ,
368+ queueconfigdefault .NewStore (),
369+ scf ,
370+ registry ,
371+ stovepipemq .TopicKeyProcess ,
372+ "stovepipe-process" ,
373+ )
374+ if err := c .Register (processController ); err != nil {
375+ return count , fmt .Errorf ("failed to register process controller: %w" , err )
376+ }
377+ count ++
378+
379+ buildController := build .NewController (logger , scope , store , brf , registry , stovepipemq .TopicKeyBuild , "stovepipe-build" )
380+ if err := c .Register (buildController ); err != nil {
381+ return count , fmt .Errorf ("failed to register build controller: %w" , err )
382+ }
383+ count ++
384+
385+ return count , nil
386+ }
387+
388+ // registerDLQControllers creates one DLQ reconciler per primary stage and
389+ // registers them with c, returning how many were registered.
390+ func registerDLQControllers (
391+ c consumer.Consumer ,
392+ logger * zap.SugaredLogger ,
393+ scope tally.Scope ,
394+ store storage.Storage ,
395+ registry consumer.TopicRegistry ,
396+ ) (int , error ) {
397+ var count int
398+
399+ processDLQController := dlq .NewController (logger , scope , store , dlq .TopicKey (stovepipemq .TopicKeyProcess ), "stovepipe-process-dlq" )
400+ if err := c .Register (processDLQController ); err != nil {
401+ return count , fmt .Errorf ("failed to register process dlq controller: %w" , err )
402+ }
403+ count ++
404+
405+ return count , nil
406+ }
407+
341408// newTopicRegistry builds the TopicRegistry for Stovepipe's internal pipeline queues. ingest
342- // publishes to process; process publishes admitted requests to the publish-only build topic.
343- // The process_dlq topic is the dead-letter destination the queue backend routes to (per
344- // DefaultSubscriptionConfig's DLQ.TopicSuffix) when the process controller exhausts retries .
409+ // publishes to the process topic and the process consumer subscribes to it; process publishes
410+ // to the build topic and the build consumer subscribes to it. The buildsignal topic is added
411+ // once the buildsignal controller lands to consume it .
345412func newTopicRegistry (q extqueue.Queue , subscriberName string ) (consumer.TopicRegistry , error ) {
346413 return consumer .NewTopicRegistry ([]consumer.TopicConfig {
347414 {
@@ -356,6 +423,9 @@ func newTopicRegistry(q extqueue.Queue, subscriberName string) (consumer.TopicRe
356423 Key : stovepipemq .TopicKeyBuild ,
357424 Name : "build" ,
358425 Queue : q ,
426+ Subscription : extqueue .DefaultSubscriptionConfig (
427+ subscriberName , "stovepipe-build" ,
428+ ),
359429 },
360430 {
361431 Key : dlq .TopicKey (stovepipemq .TopicKeyProcess ),
0 commit comments