Skip to content

feat: [#667] Registering service providers don't dependent order#1097

Merged
hwbrzzl merged 5 commits intomasterfrom
bowen/#667
Jun 29, 2025
Merged

feat: [#667] Registering service providers don't dependent order#1097
hwbrzzl merged 5 commits intomasterfrom
bowen/#667

Conversation

@hwbrzzl
Copy link
Contributor

@hwbrzzl hwbrzzl commented Jun 28, 2025

📑 Description

Closes goravel/goravel#667

I'll create another PR for all service provider files and packages.

This pull request introduces several changes to improve service provider handling, error messaging, and dependency management in the application. The most notable updates include adding dependency and binding methods to service providers, implementing a topological sort for service provider dependencies, and replacing the ArtisanFacadeNotSet error with ConsoleFacadeNotSet for better clarity. Below are the key changes grouped by theme:

Service Provider Enhancements:

  • Added Bindings, Dependencies, and ProvideFor methods to multiple service providers (cache/service_provider.go, database/service_provider.go, foundation/console/package_make_command_stubs.go). These methods define bindings, dependencies, and provide-for relationships to facilitate dependency management. [1] [2] [3]

  • Implemented a sortConfiguredServiceProviders function in foundation/application.go to perform a topological sort of service providers based on their dependencies and provide-for relationships. This ensures proper initialization order and detects circular dependencies.

Error Handling Improvements:

  • Replaced the ArtisanFacadeNotSet error with a more descriptive ConsoleFacadeNotSet error across multiple files, improving clarity in error messages related to the artisan facade. [1] [2] [3] [4] [5] [6] [7]

  • Added new error types: ServiceProviderCycle for circular dependency detection and ConsoleProvidersNotArray for invalid app.providers configuration. These errors enhance robustness in service provider management. [1] [2]

Dependency Management:

  • Modified getConfiguredServiceProviders in foundation/application.go to cache sorted service providers and handle invalid configurations gracefully.

  • Enhanced the bootArtisan and setTimezone methods to use the new error types for better error reporting when facades are not initialized. [1] [2]

✅ Checks

  • Added test cases for my code

Copilot AI review requested due to automatic review settings June 28, 2025 04:28
@hwbrzzl hwbrzzl requested a review from a team as a code owner June 28, 2025 04:28
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors service provider handling to support explicit dependencies and ordering, improves error clarity by replacing ArtisanFacadeNotSet with ConsoleFacadeNotSet, and adds a topological sort (with cycle detection) for configured service providers.

  • Added Bindings, Dependencies, and ProvideFor methods to key service providers and a sortConfiguredServiceProviders function with cycle detection.
  • Replaced all uses of ArtisanFacadeNotSet with ConsoleFacadeNotSet and introduced ConsoleProvidersNotArray.
  • Updated application initialization to cache and sort configured providers and enhanced related tests.

Reviewed Changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.

Show a summary per file
File Description
testing/test_case.go Panic now uses ConsoleFacadeNotSet instead of ArtisanFacadeNotSet
testing/service_provider.go Updated error logging to use ConsoleFacadeNotSet
testing/docker/database_test.go Test expectations updated to expect ConsoleFacadeNotSet
testing/docker/database.go NewDatabase returns ConsoleFacadeNotSet instead of old error
schedule/service_provider.go Replaced ArtisanFacadeNotSet with ConsoleFacadeNotSet
foundation/console/package_make_command_stubs.go Added Bindings, Dependencies, ProvideFor stubs
foundation/application_test.go Added tests for sortConfiguredServiceProviders and detectCycle
foundation/application.go Implemented caching, topological sort of providers, and error updates
errors/list.go Added ConsoleFacadeNotSet, ConsoleProvidersNotArray, and ServiceProviderCycle
database/service_provider.go Added provider dependency metadata methods
cache/service_provider.go Added provider dependency metadata methods
Comments suppressed due to low confidence (2)

errors/list.go:7

  • [nitpick] The error message includes context-specific instructions ("skipping artisan command execution"), which may not apply in all initialization paths. Consider simplifying to a generic message (e.g., "console facade is not initialized") and handle action-specific logging where it occurs.
	ConsoleFacadeNotSet     = New("console facade is not initialized, skipping artisan command execution")

errors/list.go:40

  • [nitpick] This error message is grammatically awkward. Consider rephrasing to improve clarity, for example: "app.providers configuration is not a []foundation.ServiceProvider; service provider registration skipped."
	ConsoleProvidersNotArray = New("the app.providers configuration is not of type []foundation.ServiceProvider, skipping registering service providers")

@codecov
Copy link

codecov bot commented Jun 28, 2025

Codecov Report

Attention: Patch coverage is 81.31313% with 37 lines in your changes missing coverage. Please review.

Project coverage is 71.45%. Comparing base (b98d29f) to head (6140650).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
auth/service_provider.go 0.00% 11 Missing ⚠️
cache/service_provider.go 0.00% 11 Missing ⚠️
foundation/application.go 92.66% 11 Missing ⚠️
testing/test_case.go 0.00% 2 Missing ⚠️
schedule/service_provider.go 0.00% 1 Missing ⚠️
testing/service_provider.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1097      +/-   ##
==========================================
+ Coverage   71.16%   71.45%   +0.29%     
==========================================
  Files         183      183              
  Lines       12826    13057     +231     
==========================================
+ Hits         9127     9330     +203     
- Misses       3330     3358      +28     
  Partials      369      369              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

return envFilePath
}

func sortConfiguredServiceProviders(providers []foundation.ServiceProvider) []foundation.ServiceProvider {
Copy link
Member

Choose a reason for hiding this comment

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

We can create a separate package for the DAG (Directed Acyclic Graph) instead of including it in application.go. This package will handle all the heavy lifting, like topological sorting, cycle detection, and other related operations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, not very clear, welcome to create a related issue and discuss it first.

type ServiceProvider struct {
}

func (r *ServiceProvider) Bindings() []string {
Copy link
Member

Choose a reason for hiding this comment

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

Is this used to bind the same service to multiple keys?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the case below: multiple bindings are in the same service provider.

image


func (r *ServiceProvider) Bindings() []string {
return []string{
contracts.BindingOrm,
Copy link
Member

Choose a reason for hiding this comment

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

We can move this to a different package, bindings. I'm not sure contracts conveys the right meaning here. Then we can use bindings.Orm.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's fine, please check #868

}

// Create a map for quick lookup of providers by their binding names
providerMap := make(map[string]foundation.ServiceProvider)
Copy link
Member

Choose a reason for hiding this comment

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

We may not need providerMap, since both providerMap and bindingToProvider serve the same purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch

Comment on lines +398 to +414
for _, provider := range providers {
for _, binding := range getBindings(provider) {
providerMap[binding] = provider
bindingToProvider[binding] = provider
}
}

// Create adjacency list for dependency graph
graph := make(map[string][]string)
inDegree := make(map[string]int)

// Initialize inDegree for all providers
for _, provider := range providers {
for _, binding := range getBindings(provider) {
inDegree[binding] = 0
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
for _, provider := range providers {
for _, binding := range getBindings(provider) {
providerMap[binding] = provider
bindingToProvider[binding] = provider
}
}
// Create adjacency list for dependency graph
graph := make(map[string][]string)
inDegree := make(map[string]int)
// Initialize inDegree for all providers
for _, provider := range providers {
for _, binding := range getBindings(provider) {
inDegree[binding] = 0
}
}
// Create adjacency list for dependency graph
graph := make(map[string][]string)
inDegree := make(map[string]int)
for _, provider := range providers {
for _, binding := range getBindings(provider) {
providerMap[binding] = provider
bindingToProvider[binding] = provider
inDegree[binding] = 0
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch

@hwbrzzl hwbrzzl requested a review from a team June 28, 2025 13:30
@hwbrzzl hwbrzzl merged commit 087843f into master Jun 29, 2025
14 checks passed
@hwbrzzl hwbrzzl deleted the bowen/#667 branch June 29, 2025 02:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Registering service providers don't dependent order

3 participants