@@ -25,7 +25,6 @@ import (
2525 "github.com/riverqueue/river/internal/middlewarelookup"
2626 "github.com/riverqueue/river/internal/notifier"
2727 "github.com/riverqueue/river/internal/notifylimiter"
28- "github.com/riverqueue/river/internal/pluginconfig"
2928 "github.com/riverqueue/river/internal/rivercommon"
3029 "github.com/riverqueue/river/internal/rivermiddleware"
3130 "github.com/riverqueue/river/internal/workunit"
@@ -245,6 +244,8 @@ type Config struct {
245244 //
246245 // If a type in Hooks also implements rivertype.Middleware, it will be
247246 // installed as middleware too.
247+ //
248+ // Deprecated: Use Plugins instead.
248249 Hooks []rivertype.Hook
249250
250251 // Logger is the structured logger to use for logging purposes. If none is
@@ -281,20 +282,22 @@ type Config struct {
281282 //
282283 // If a type in Middleware also implements rivertype.Hook, it will be
283284 // installed as a hook too.
285+ //
286+ // Deprecated: Use Plugins instead.
284287 Middleware []rivertype.Middleware
285288
286- // Plugins contains extensions installed globally as both hooks and
287- // middleware .
289+ // Plugins contains extensions installed globally as hooks, middleware, or
290+ // both .
288291 //
289- // A plugin must implement both rivertype.Hook and rivertype.Middleware. It
290- // may embed PluginDefaults, or embed both HookDefaults and
291- // MiddlewareDefaults directly, then implement any operation-specific hook or
292- // middleware interfaces it needs.
292+ // A type qualifies as a plugin by implementing [rivertype.Plugin]. Most
293+ // existing hook and middleware implementations already do this by embedding
294+ // HookDefaults or MiddlewareDefaults. If a type participates on both sides,
295+ // it may embed PluginDefaults, or embed both HookDefaults and
296+ // MiddlewareDefaults directly and define its own IsPlugin method, then
297+ // implement any operation-specific hook or middleware interfaces it needs.
293298 //
294- // Hooks and Middleware are still supported. If a type in Hooks also
295- // implements middleware, or a type in Middleware also implements hooks, River
296- // will install it on both sides automatically. The Plugins list exists as a
297- // generic place for new extensions to be registered.
299+ // Hooks and Middleware are still supported for backward compatibility, but
300+ // Plugins is the preferred place to register new extensions.
298301 Plugins []rivertype.Plugin
299302
300303 // PeriodicJobs are a set of periodic jobs to run at the specified intervals
@@ -542,6 +545,83 @@ func (c *Config) WithDefaults() *Config {
542545 }
543546}
544547
548+ func effectiveHooksForConfig (config * Config ) []rivertype.Hook {
549+ configuredMiddleware := middlewareFromConfig (config )
550+ hooks := make ([]rivertype.Hook , 0 , len (config .Hooks )+ len (configuredMiddleware )+ len (config .Plugins ))
551+ hooks = append (hooks , config .Hooks ... )
552+
553+ for _ , middleware := range configuredMiddleware {
554+ if hook , ok := middleware .(rivertype.Hook ); ok {
555+ hooks = append (hooks , hook )
556+ }
557+ }
558+
559+ for _ , plugin := range config .Plugins {
560+ if plugin == nil {
561+ continue
562+ }
563+
564+ if hook , ok := plugin .(rivertype.Hook ); ok {
565+ hooks = append (hooks , hook )
566+ }
567+ }
568+
569+ return hooks
570+ }
571+
572+ func effectiveMiddlewareForConfig (config * Config ) []rivertype.Middleware {
573+ configuredMiddleware := middlewareFromConfig (config )
574+ middleware := make ([]rivertype.Middleware , 0 , len (config .Hooks )+ len (configuredMiddleware )+ len (config .Plugins ))
575+ middleware = append (middleware , configuredMiddleware ... )
576+
577+ for _ , hook := range config .Hooks {
578+ if middlewareItem , ok := hook .(rivertype.Middleware ); ok {
579+ middleware = append (middleware , middlewareItem )
580+ }
581+ }
582+
583+ for _ , plugin := range config .Plugins {
584+ if plugin == nil {
585+ continue
586+ }
587+
588+ if middlewareItem , ok := plugin .(rivertype.Middleware ); ok {
589+ middleware = append (middleware , middlewareItem )
590+ }
591+ }
592+
593+ return middleware
594+ }
595+
596+ func middlewareFromConfig (config * Config ) []rivertype.Middleware {
597+ middleware := make ([]rivertype.Middleware , 0 ,
598+ len (config .Middleware )+ len (config .JobInsertMiddleware )+ len (config .WorkerMiddleware ))
599+ middleware = append (middleware , config .Middleware ... )
600+
601+ for _ , jobInsertMiddleware := range config .JobInsertMiddleware {
602+ middleware = append (middleware , jobInsertMiddleware )
603+ }
604+
605+ outerLoop:
606+ for _ , workerMiddleware := range config .WorkerMiddleware {
607+ // Don't add the middleware if it also implements JobInsertMiddleware
608+ // and the instance has been added to config.JobInsertMiddleware. This
609+ // is a hedge to make sure we don't accidentally double add middleware
610+ // as we've converted over to the unified config.Middleware setting.
611+ if workerMiddlewareAsJobInsertMiddleware , ok := workerMiddleware .(rivertype.JobInsertMiddleware ); ok {
612+ for _ , jobInsertMiddleware := range config .JobInsertMiddleware {
613+ if workerMiddlewareAsJobInsertMiddleware == jobInsertMiddleware {
614+ continue outerLoop
615+ }
616+ }
617+ }
618+
619+ middleware = append (middleware , workerMiddleware )
620+ }
621+
622+ return middleware
623+ }
624+
545625func (c * Config ) validate () error {
546626 if c .CancelledJobRetentionPeriod < - 1 {
547627 return errors .New ("CancelledJobRetentionPeriod time cannot be less than zero, except for -1 (infinite)" )
@@ -824,9 +904,8 @@ func NewClient[TTx any](driver riverdriver.Driver[TTx], config *Config) (*Client
824904 }
825905 }
826906
827- configuredMiddleware := middlewareFromConfig (config )
828- effectiveHooks := pluginconfig .Hooks (config .Hooks , configuredMiddleware , config .Plugins )
829- effectiveMiddleware := pluginconfig .Middleware (config .Hooks , configuredMiddleware , config .Plugins )
907+ effectiveHooks := effectiveHooksForConfig (config )
908+ effectiveMiddleware := effectiveMiddlewareForConfig (config )
830909
831910 for _ , hook := range effectiveHooks {
832911 if withBaseService , ok := hook .(baseservice.WithBaseService ); ok {
@@ -1075,35 +1154,6 @@ func NewClient[TTx any](driver riverdriver.Driver[TTx], config *Config) (*Client
10751154 return client , nil
10761155}
10771156
1078- func middlewareFromConfig (config * Config ) []rivertype.Middleware {
1079- middleware := make ([]rivertype.Middleware , 0 ,
1080- len (config .Middleware )+ len (config .JobInsertMiddleware )+ len (config .WorkerMiddleware ))
1081- middleware = append (middleware , config .Middleware ... )
1082-
1083- for _ , jobInsertMiddleware := range config .JobInsertMiddleware {
1084- middleware = append (middleware , jobInsertMiddleware )
1085- }
1086-
1087- outerLoop:
1088- for _ , workerMiddleware := range config .WorkerMiddleware {
1089- // Don't add the middleware if it also implements JobInsertMiddleware
1090- // and the instance has been added to config.JobInsertMiddleware. This
1091- // is a hedge to make sure we don't accidentally double add middleware
1092- // as we've converted over to the unified config.Middleware setting.
1093- if workerMiddlewareAsJobInsertMiddleware , ok := workerMiddleware .(rivertype.JobInsertMiddleware ); ok {
1094- for _ , jobInsertMiddleware := range config .JobInsertMiddleware {
1095- if workerMiddlewareAsJobInsertMiddleware == jobInsertMiddleware {
1096- continue outerLoop
1097- }
1098- }
1099- }
1100-
1101- middleware = append (middleware , workerMiddleware )
1102- }
1103-
1104- return middleware
1105- }
1106-
11071157// Start starts the client's job fetching and working loops. Once this is called,
11081158// the client will run in a background goroutine until stopped. All jobs are
11091159// run with a context inheriting from the provided context, but with a timeout
0 commit comments