Skip to content

Conversation

@vpapidokha
Copy link
Collaborator

@vpapidokha vpapidokha commented Apr 11, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a profiling endpoint to access performance diagnostics.
    • Added new methods for lease management, including lease creation, revival, and cache operations.
    • Enhanced server configuration with new environment variables for profiling, storage type, and caching options.
  • Refactor

    • Streamlined application initialization and request handling for improved reliability.
    • Simplified error handling in lease management processes.
    • Improved concurrency control and lease management capabilities in the storage structure.
  • Chores

    • Enhanced connection management and error handling for smoother overall operation.
    • Updated server configuration to support profiling capabilities.

These improvements deliver a more robust and easier-to-monitor application experience.

@coderabbitai
Copy link

coderabbitai bot commented Apr 11, 2025

Walkthrough

The changes update the application’s architecture by integrating an external storage connection into the Application struct and its methods. The constructor and handler functions now require this storage connection as a parameter. A new bootstrap package is introduced to handle the initialization of the cache, storage connection, and application instance. The HTTP delivery layer is enhanced with a pprof endpoint and updated handler signatures, while the serve process now utilizes the bootstrap logic for streamlined initialization.

Changes

File(s) Summary
internal/application/application.go Added StorageConnection field to Application; updated New, removed GetLeaseHandler, added CreateLease, and replaced KeepaliveHandler with ReviveLease.
internal/application/application_test.go Renamed tests to focus on CreateLease and ReviveLease; updated test structure to reflect new method signatures and removed old handler tests.
internal/bootstrap/bootstrap.go New file. Added newCache, newStorageConnection, and NewApplication to centralize application initialization and component setup.
internal/delivery/http/server.go Added pprof endpoint import and route; updated handleLease and handleKeepalive to include detailed error handling and logging.
internal/delivery/serve.go Restructured application initialization: removed cache logic and now uses bootstrap.NewApplication with enhanced error handling.
internal/application/command/leasemanagement/leaseManagement.go Removed DefaultLeaseDurationSeconds; updated CreateLease to simplify its signature and logic.
internal/application/command/leasemanagement/leasemanagement_test.go Updated TestCreateLease to reflect changes in CreateLease function signature.
internal/config/config.go Added PPROFEnabled boolean field to ServerCfg struct for profiling capabilities.
internal/delivery/http/server_test.go New file. Introduced unit tests for HTTP server handling lease and keepalive requests, validating various scenarios.
internal/infrastructure/cache/cache.go Added new type LeaseCacheRecord with fields for Status and ID.
README.md Added new environment variables for profiling, storage type, and caching; modified existing variable for etcd address format.
internal/infrastructure/storage/mock/mock.go Added DefaultPrefix constant; updated Storage struct for concurrency control and lease management; added New() constructor.

Sequence Diagram(s)

sequenceDiagram
    participant S as Serve
    participant B as Bootstrap
    participant C as Cache
    participant ST as Storage
    participant A as Application

    S->>B: NewApplication(ctx, config)
    B->>C: newCache(cfg) (if caching enabled)
    B->>ST: newStorageConnection(cfg)
    B->>A: Application.New(ctx, config, storage, cache)
    A-->>B: Application instance
    B-->>S: Application instance
Loading
sequenceDiagram
    participant Client as Client
    participant Server as Server
    participant Handler as LeaseHandler
    participant Storage as Storage

    Client->>Server: HTTP Request (/lease or /keepalive)
    Server->>Handler: Call CreateLease/ReviveLease(ctx, storage, ...)
    Handler->>Storage: Process request using storage connection
    Storage-->>Handler: Return result
    Handler-->>Server: Response generated
    Server-->>Client: HTTP Response
Loading

Possibly related PRs

Poem

Hopping through bytes with joyful might,
I found a storage connection shining bright.
Constructors now await an external friend,
With tests and bootstrap, our code shall transcend.
I, the rabbit coder, celebrate this change in flight! 🐰

Happy coding under the moonlit byte!

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69f2669 and 3c2e365.

📒 Files selected for processing (2)
  • internal/application/application.go (1 hunks)
  • internal/delivery/http/server.go (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
internal/delivery/http/server.go (4)
internal/infrastructure/metrics/metrics.go (2)
  • LeaseOperationDuration (21-28)
  • LeaseOperationGet (9-9)
example/client.go (1)
  • Lease (21-26)
internal/application/command/leasemanagement/leaseManagement.go (2)
  • CreateLease (17-47)
  • ReviveLease (49-56)
internal/infrastructure/storage/storage.go (2)
  • StatusAccepted (8-8)
  • StatusCreated (9-9)
internal/application/application.go (4)
internal/infrastructure/cache/cache.go (3)
  • Cache (11-17)
  • New (34-45)
  • LeaseCacheRecord (29-32)
internal/infrastructure/storage/storage.go (1)
  • Storage (12-16)
internal/application/command/leasemanagement/leaseManagement.go (2)
  • CreateLease (17-47)
  • ReviveLease (49-56)
internal/infrastructure/metrics/metrics.go (2)
  • LeaseOperations (13-19)
  • CacheOperations (30-36)
🔇 Additional comments (10)
internal/application/application.go (6)

15-20: Fields made unexported for better encapsulation

This change makes all Application struct fields unexported (private), which aligns with the best practice mentioned in the previous review comment. This encapsulation prevents direct manipulation of the application's internal state from outside the package.


22-29: Good integration of storage connection

Adding the storage connection as a parameter to the constructor and as a field in the Application struct is a solid architectural improvement. This change matches the PR objective of making a common connection to the storage adapter and helps to avoid creating multiple connections that could lead to high memory consumption.


31-45: Simplified and well-structured lease creation

The CreateLease method properly delegates to the leasemanagement package while handling errors and metrics appropriately. This design separates concerns well - the application layer coordinates the operation while the domain logic stays in the leasemanagement package.


47-57: ReviveLease implementation is clean and focused

This method provides a simple interface for lease revival while properly handling errors and tracking metrics. The error logging and metric incrementation follow consistent patterns with the CreateLease method.


59-69: Null safety check in CheckLeasePresenceInCache

The method properly checks if the cache is nil before attempting to use it, which prevents potential nil pointer dereference errors. The logic is straightforward and focused on a single responsibility.


84-93: Clean implementation of AddLeaseToCache

The AddLeaseToCache method properly checks for a nil cache to prevent potential nil pointer dereferences. The method encapsulates the cache interaction logic well, creating a proper LeaseCacheRecord with the provided parameters.

internal/delivery/http/server.go (4)

3-25: Well-structured imports and constants

The addition of necessary imports and clearly defined constants improves the code's readability and maintainability. The defaultLeaseTTLHeader and defaultLeaseDuration constants prevent magic strings/values in the code.


45-47: Good addition of conditional pprof endpoint

Adding the pprof endpoint only when PPROFEnabled is true is a good practice for security. This gives you profiling capabilities when needed without exposing them unnecessarily in production environments.


107-120: Appropriate status code handling based on lease status

The switch statement correctly sets HTTP status codes based on the lease status, which is a good practice for RESTful APIs. The error handling for writing the response is also appropriate.


151-153: Simplified health endpoint

The handleHealth method has been appropriately simplified to just return a 200 OK status code, which is sufficient for a basic health check endpoint.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
internal/bootstrap/bootstrap.go (1)

30-38: Clean cache initialization handling.

The function correctly handles both enabled and disabled cache scenarios, with appropriate logging. However, consider enhancing error handling by checking for any potential initialization errors when creating the cache.

func newCache(cfg *config.Config) (*cache.Cache, error) {
	if cfg.Cache.Enabled {
		log.Info("Cache is enabled")
-		return cache.New(cfg.Cache.Size), nil
+		cache := cache.New(cfg.Cache.Size)
+		if cache == nil {
+			return nil, fmt.Errorf("failed to initialize cache")
+		}
+		return cache, nil
	}

	log.Info("Cache is disabled")
	return nil, nil
}
internal/application/application_test.go (1)

89-271: Consider reusing a single mock storage instance across test cases

Currently, each test function creates its own storage connection instance. Since the mock implementation has no state, you could potentially define a single instance at the package level to reduce redundancy.

package application

import (
	// existing imports...
	"github.com/tentens-tech/shared-lock/internal/infrastructure/storage/mock"
)

// Add a single mock storage instance at package level
+var sharedMockStorage = &mock.Storage{}

func createTestConfig() *config.Config {
	// existing code...
}

func TestGetLeaseHandler(t *testing.T) {
	// ...
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// ...
-			storageConnection := &mock.Storage{}
+			storageConnection := sharedMockStorage
			// ...
		})
	}
}

// Apply similar changes to other test functions
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6dd1e93 and 4193773.

📒 Files selected for processing (5)
  • internal/application/application.go (2 hunks)
  • internal/application/application_test.go (10 hunks)
  • internal/bootstrap/bootstrap.go (1 hunks)
  • internal/delivery/http/server.go (3 hunks)
  • internal/delivery/serve.go (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
internal/delivery/serve.go (1)
internal/bootstrap/bootstrap.go (1)
  • NewApplication (40-54)
internal/delivery/http/server.go (2)
internal/application/application.go (2)
  • GetLeaseHandler (45-123)
  • KeepaliveHandler (125-156)
internal/config/config.go (1)
  • Config (28-33)
internal/application/application_test.go (2)
internal/infrastructure/storage/mock/mock.go (1)
  • Storage (9-9)
internal/application/application.go (2)
  • GetLeaseHandler (45-123)
  • KeepaliveHandler (125-156)
🔇 Additional comments (18)
internal/bootstrap/bootstrap.go (2)

16-28: Well-structured storage connection factory function.

This new function effectively handles different storage types (etcd or mock) based on the configuration. Error handling is appropriate, and the code is clean and maintainable.


40-54: Good application initialization with proper error handling.

The function correctly orchestrates the initialization of components and handles errors appropriately. The approach of externalizing the bootstrap logic makes the codebase more maintainable and follows the Separation of Concerns principle.

internal/application/application.go (4)

29-34: Good addition of StorageConnection field to the Application struct.

Adding the StorageConnection field to the Application struct allows for a single shared storage connection, which should help reduce memory consumption as mentioned in the PR title.


36-43: Constructor updated correctly to include storage connection.

The New function signature has been properly updated to accept the storage connection as a parameter, and the struct initialization has been adjusted accordingly.


45-123: GetLeaseHandler now correctly accepts the storage connection.

The handler has been updated to receive the storage connection as a parameter instead of creating it internally. This change is consistent with the PR's goal of reducing memory consumption by reusing a single storage connection.


125-156: KeepaliveHandler now correctly accepts the storage connection.

Similar to GetLeaseHandler, this function has been updated to receive the storage connection as a parameter, maintaining consistency throughout the codebase.

internal/delivery/http/server.go (4)

6-7: Added pprof support for performance profiling.

Good addition of the pprof package import, which will enable runtime profiling capabilities. This is particularly useful for identifying potential memory issues.


30-31: Added pprof HTTP endpoint.

This correctly adds a handler for the pprof debugging endpoint, which is essential for runtime profiling. Ensure this endpoint is properly secured in production environments.

When deployed to production, ensure that the pprof endpoint is not publicly accessible, as it could expose sensitive information. Consider adding authentication or IP-based restrictions for this endpoint.


43-45: handleLease now uses the storage connection from the app.

The handler now correctly passes the application's storage connection to the GetLeaseHandler function, implementing the shared connection approach.


47-49: handleKeepalive now uses the storage connection from the app.

The handler now correctly passes the application's storage connection to the KeepaliveHandler function, implementing the shared connection approach.

internal/delivery/serve.go (2)

11-12: Updated import to use the new bootstrap package.

Correctly replaced the application import with the bootstrap import to leverage the new initialization logic.


40-44: Improved application initialization with proper error handling.

The code now uses the bootstrap package to create the application instance, which includes initializing both the cache and storage connection. The error handling has been improved to catch initialization failures.

internal/application/application_test.go (6)

19-19: New import correctly added for mock storage

The addition of the mock package import is necessary to support the refactored architecture that uses an external storage connection.


89-90: Storage connection correctly integrated in TestGetLeaseHandler

The mock storage connection is properly created and passed to the GetLeaseHandler function, aligning with the new signature that takes an explicit storage connection. This change supports the PR objective of reusing storage connections to reduce memory consumption.

Also applies to: 111-111


126-127: Storage connection correctly integrated in TestGetLeaseHandlerConcurrent

The mock storage instance is properly created and passed to the handler in the concurrent test scenario. This ensures consistency with the updated handler signature.

Also applies to: 146-146


164-165: Storage connection correctly integrated in TestGetLeaseHandlerMemoryUsage

The memory usage test now properly includes the storage connection. This test is particularly relevant to the PR objective as it verifies that memory consumption remains within acceptable limits.

Also applies to: 183-183


238-238: Storage connection correctly integrated in TestKeepaliveHandler

The KeepaliveHandler test cases now include the mock storage connection, correctly reflecting the updated handler signature.

Also applies to: 243-243


259-259: Storage connection correctly integrated in TestKeepaliveHandlerConcurrent

The concurrent tests for the KeepaliveHandler function now include the mock storage connection, maintaining consistency with the updated architecture.

Also applies to: 271-271

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (2)
internal/application/application.go (1)

31-45: New CreateLease method implementation.

The method correctly utilizes the storage connection from the Application struct. However, there seems to be a discrepancy in the metrics label - using LeaseOperationGet for what is actually a lease creation operation.

Consider updating the metrics label to something more specific to the creation operation:

- metrics.LeaseOperations.WithLabelValues(metrics.LeaseOperationGet, "error").Inc()
+ metrics.LeaseOperations.WithLabelValues("create", "error").Inc()

- metrics.LeaseOperations.WithLabelValues(metrics.LeaseOperationGet, leaseStatus).Inc()
+ metrics.LeaseOperations.WithLabelValues("create", leaseStatus).Inc()

Or define a new constant LeaseOperationCreate in the metrics package.

internal/delivery/http/server_test.go (1)

165-206: Memory usage test needs validation

The memory usage test is a good way to ensure that the application doesn't consume excessive memory when handling multiple leases. However, the 50MB threshold seems arbitrary.

Consider basing this threshold on benchmarks from previous versions or actual performance requirements. Also, consider using a percentage increase rather than an absolute value, which would make the test more robust across different environments.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4193773 and cace321.

📒 Files selected for processing (8)
  • internal/application/application.go (1 hunks)
  • internal/application/application_test.go (1 hunks)
  • internal/application/command/leasemanagement/leaseManagement.go (2 hunks)
  • internal/application/command/leasemanagement/leasemanagement_test.go (1 hunks)
  • internal/config/config.go (2 hunks)
  • internal/delivery/http/server.go (3 hunks)
  • internal/delivery/http/server_test.go (1 hunks)
  • internal/infrastructure/cache/cache.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
internal/application/command/leasemanagement/leasemanagement_test.go (1)
internal/application/command/leasemanagement/leaseManagement.go (1)
  • CreateLease (17-47)
internal/application/command/leasemanagement/leaseManagement.go (2)
internal/infrastructure/storage/storage.go (1)
  • Storage (12-16)
internal/application/command/leasemanagement/lease.go (1)
  • Lease (7-12)
internal/delivery/http/server_test.go (5)
internal/config/config.go (2)
  • Config (28-33)
  • NewConfig (70-103)
internal/infrastructure/cache/cache.go (3)
  • Cache (11-17)
  • New (34-45)
  • LeaseCacheRecord (29-32)
internal/application/application.go (2)
  • Application (15-20)
  • New (22-29)
internal/delivery/http/server.go (1)
  • New (33-37)
internal/infrastructure/storage/storage.go (2)
  • StatusAccepted (8-8)
  • StatusCreated (9-9)
internal/application/application.go (7)
internal/config/config.go (1)
  • Config (28-33)
internal/infrastructure/storage/mock/mock.go (1)
  • Storage (9-9)
internal/infrastructure/storage/storage.go (1)
  • Storage (12-16)
internal/delivery/http/server.go (1)
  • New (33-37)
internal/application/command/leasemanagement/leaseManagement.go (1)
  • CreateLease (17-47)
internal/application/command/leasemanagement/lease.go (1)
  • Lease (7-12)
internal/infrastructure/metrics/metrics.go (3)
  • LeaseOperations (13-19)
  • LeaseOperationGet (9-9)
  • LeaseOperationProlong (8-8)
internal/delivery/http/server.go (5)
internal/infrastructure/metrics/metrics.go (3)
  • LeaseOperationDuration (21-28)
  • LeaseOperationGet (9-9)
  • CacheOperations (30-36)
example/client.go (1)
  • Lease (21-26)
internal/infrastructure/cache/cache.go (1)
  • LeaseCacheRecord (29-32)
internal/application/command/leasemanagement/leaseManagement.go (2)
  • CreateLease (17-47)
  • ReviveLease (49-56)
internal/infrastructure/storage/storage.go (2)
  • StatusAccepted (8-8)
  • StatusCreated (9-9)
internal/application/application_test.go (5)
internal/infrastructure/storage/mock/mock.go (1)
  • Storage (9-9)
internal/infrastructure/storage/storage.go (2)
  • StatusCreated (9-9)
  • StatusAccepted (8-8)
internal/application/application.go (1)
  • New (22-29)
internal/infrastructure/cache/cache.go (2)
  • New (34-45)
  • LeaseCacheRecord (29-32)
internal/application/command/leasemanagement/leaseManagement.go (2)
  • CreateLease (17-47)
  • ReviveLease (49-56)
🪛 GitHub Actions: Docker Build & Push
internal/delivery/http/server_test.go

[error] Failed to unmarshal request body, invalid character 'i' looking for beginning of value.


[error] Failed to parse lease id from string, leaseIDString: invalid-id, strconv.ParseInt: parsing 'invalid-id': invalid syntax.


[error] Failed to parse lease id from string, leaseIDString: , strconv.ParseInt: parsing '': invalid syntax.

internal/application/application_test.go

[error] 75-80: TestApplication_CreateLease/Lease_already_exists failed: Not equal: expected 'accepted', actual 'created'.


[error] 120-120: TestApplication_ReviveLease/Failed_lease_revival failed: An error is expected but got nil.


[error] 80-80: TestApplication_CreateLease/Successful_lease_creation failed: Should be true.


[error] 75-76: TestApplication_CreateLease/Lease_already_exists failed: Not equal: expected 456, actual 123.

🔇 Additional comments (17)
internal/infrastructure/cache/cache.go (1)

29-32: New struct added for lease caching.

This LeaseCacheRecord struct looks good. It provides a clean way to cache lease status and ID information, which aligns with the PR objective of optimizing memory consumption by reusing the storage connection.

internal/config/config.go (2)

35-38: Added pprof profiling configuration.

The addition of the PPROFEnabled field in the ServerCfg struct is a good improvement for debugging capabilities.


78-80: Configuration setup for pprof.

Good implementation. The configuration correctly reads from environment variables with appropriate defaults.

internal/application/application.go (3)

15-20: Improved Application struct with storage connection.

Adding StorageConnection as a field in the Application struct is a good architectural improvement. This change aligns with the PR objective of making a common connection to the storage adapter, which should help reduce memory consumption by avoiding multiple connections.


22-29: Updated constructor with storage connection parameter.

The constructor now properly accepts and initializes the storage connection. This is a good improvement that makes the dependency explicit and allows for better resource management.


47-57: New ReviveLease method implementation.

This method correctly implements the lease revival functionality using the storage connection from the Application struct. The error handling and metrics recording are appropriate.

internal/application/command/leasemanagement/leasemanagement_test.go (1)

148-149: Updated test to match new function signature.

The test now correctly calls the CreateLease function with the updated parameter list, which matches the function signature in the relevant code snippets.

internal/application/command/leasemanagement/leaseManagement.go (3)

13-15: Note the removal of DefaultLeaseDurationSeconds constant

The DefaultLeaseDurationSeconds constant has been removed from this file, and only DefaultPrefix remains. Make sure this change is intentional and that any code that previously relied on this constant has been updated.


17-17: Updated function signature to remove the data parameter

The CreateLease function signature has been updated to remove the data []byte parameter. This is a good simplification since the function now uses the lease value directly.


35-35: Using lease value directly for storage creation

The function now passes []byte(lease.Value) to the storage connection instead of using a separate data parameter. This is a cleaner approach that maintains the same functionality.

internal/delivery/http/server_test.go (1)

23-31: Good test infrastructure setup

The test configuration and application setup are well-structured, making it easy to create consistent test environments.

internal/delivery/http/server.go (4)

11-11: Added pprof for debugging

Good addition of the pprof package for profiling and debugging. This will be useful for identifying performance bottlenecks and memory leaks.


23-26: Added constants for lease management

Defining constants for the default lease TTL header and duration is a good practice for maintainability.


46-48: Conditional pprof endpoint activation

Good implementation of conditionally enabling the pprof endpoint based on configuration. This prevents exposing sensitive debugging information in production environments.


163-165: Simplified health endpoint

The health endpoint has been simplified to just return a 200 status code. This is appropriate for a basic health check.

internal/application/application_test.go (2)

128-161: Good concurrent operations test

The concurrent operations test is well designed to verify that the application can handle multiple simultaneous lease operations. This is important for real-world scenarios where the application will receive many requests.


162-181: Testing with cache disabled

Good addition of a test for the cache-disabled scenario. This ensures that the application works correctly even when no cache is available.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
README.md (2)

29-31: New Environment Variable Configurations

The documentation now introduces three key environment variables:

  • SHARED_LOCK_PPROF_ENABLED enables pprof debugging.
  • SHARED_LOCK_STORAGE_TYPE lets users choose between etcd and mock storage adapters.
  • SHARED_LOCK_ETCD_ADDR_LIST now uses http://localhost:2379 (changed from localhost:2379), which clarifies the expected URL scheme.

Please verify that the application’s configuration parsing correctly handles the HTTP scheme in the etcd address and that these changes align with the storage adapter updates aimed at reducing memory consumption. Also, note that markdownlint MD034 may flag the bare URL—consider wrapping the URL in angle brackets if needed.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

31-31: Bare URL used
null

(MD034, no-bare-urls)


36-37: Addition of In-Memory Cache Configuration

New variables for cache control:

  • SHARED_LOCK_CACHE_ENABLED allows in-memory caching for leases.
  • SHARED_LOCK_CACHE_SIZE specifies the maximum number of cache items.

These additions are clear and contribute to the configurability of caching behavior. For enhanced clarity, consider adding a brief note in the README explaining how enabling the cache impacts memory consumption and interacts with the new storage adapter connection introduced in this PR.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cace321 and e639795.

📒 Files selected for processing (1)
  • README.md (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
README.md

31-31: Bare URL used
null

(MD034, no-bare-urls)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
internal/infrastructure/storage/mock/mock.go (1)

43-48: Improve documentation for special lease ID case

The code returns an error for the specific lease ID 999 but doesn't document why this special case exists. This appears to be for testing the failure path in TestApplication_ReviveLease.

Consider adding a comment to explain this test-specific behavior:

func (s *Storage) KeepLeaseOnce(ctx context.Context, leaseID int64) error {
+	// Special case for testing failure scenarios - lease ID 999 is considered not found
	if leaseID == 999 {
		return fmt.Errorf("lease not found")
	}
	return nil
}
internal/delivery/http/server_test.go (1)

159-162: Add threshold explanation for memory test

The memory test asserts that allocating 1000 leases should use less than 50MB of memory, but doesn't provide reasoning for this threshold.

Add a comment explaining why 50MB is an appropriate threshold to ensure the test intent is clear and maintainable:

	maxMemoryMB := uint64(50 * 1024 * 1024)
+	// 50MB threshold based on estimated size: 1000 leases × ~1KB per lease structure with overhead
	assert.LessOrEqual(t, memoryAlloc, maxMemoryMB,
		"Memory usage should be less than 50MB for 1000 leases")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e639795 and 2f9239c.

📒 Files selected for processing (3)
  • internal/application/application_test.go (1 hunks)
  • internal/delivery/http/server_test.go (1 hunks)
  • internal/infrastructure/storage/mock/mock.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
internal/delivery/http/server_test.go (6)
internal/config/config.go (2)
  • Config (28-33)
  • NewConfig (70-103)
internal/infrastructure/storage/mock/mock.go (2)
  • Storage (13-16)
  • New (18-22)
internal/infrastructure/cache/cache.go (2)
  • Cache (11-17)
  • New (34-45)
internal/application/application.go (2)
  • Application (15-20)
  • New (22-29)
internal/delivery/http/server.go (1)
  • New (33-37)
internal/infrastructure/storage/storage.go (1)
  • StatusCreated (9-9)
internal/infrastructure/storage/mock/mock.go (2)
internal/application/command/leasemanagement/leaseManagement.go (1)
  • CreateLease (17-47)
internal/infrastructure/storage/storage.go (2)
  • StatusAccepted (8-8)
  • StatusCreated (9-9)
internal/application/application_test.go (5)
internal/infrastructure/storage/mock/mock.go (3)
  • Storage (13-16)
  • New (18-22)
  • DefaultPrefix (11-11)
internal/infrastructure/storage/storage.go (2)
  • StatusCreated (9-9)
  • StatusAccepted (8-8)
internal/application/application.go (1)
  • New (22-29)
internal/infrastructure/cache/cache.go (1)
  • New (34-45)
internal/application/command/leasemanagement/leaseManagement.go (3)
  • DefaultPrefix (14-14)
  • CreateLease (17-47)
  • ReviveLease (49-56)
🪛 GitHub Actions: Docker Build & Push
internal/delivery/http/server_test.go

[error] 110-110: Not equal: expected: 201, actual: 202 in TestGetLeaseHandlerConcurrent


[error] 110-110: Failed to parse lease id from string, leaseIDString: invalid-id, strconv.ParseInt: parsing "invalid-id": invalid syntax


[error] 110-110: Failed to parse lease id from string, leaseIDString: , strconv.ParseInt: parsing "": invalid syntax


[warning] 110-110: Can't parse value of x-lease-ttl header. Using defaultLeaseDuration for existing-key


[warning] 110-110: Can't parse value of x-lease-ttl header. Using defaultLeaseDuration for new-key


[warning] 110-110: Can't parse value of x-lease-ttl header. Using defaultLeaseDuration for cache-miss-key

🔇 Additional comments (4)
internal/delivery/http/server_test.go (2)

104-106: ⚠️ Potential issue

Add missing header in test requests

The test doesn't set the x-lease-ttl header for the request, which results in warnings in the pipeline logs about using default lease durations.

	req := httptest.NewRequest(http.MethodPost, "/lease", bytes.NewBuffer(body))
+	req.Header.Set("x-lease-ttl", "1m")

Likely an incorrect or invalid review comment.


43-46:

Details

❓ Verification inconclusive

Fix inconsistent test expectations

This test case expects a status code of http.StatusCreated (201) and a body of "123" for a cache hit with an "accepted" status, but the pipeline failure indicates that the actual status is 202.


🏁 Script executed:

#!/bin/bash
# Check if the server actually returns 201 or 202 for accepted leases

# First, look for the implementation of the handler to see status code mapping
rg -A 10 "handleLease.*func" internal/delivery/http

Length of output: 53


Please verify the correct status code for accepted leases in the tests

It appears that the test in internal/delivery/http/server_test.go (lines 43–46) currently expects a status of http.StatusCreated (201) with a response body "123", yet the pipeline indicates that the actual response is 202 (i.e. http.StatusAccepted). Since our initial automated search for the handler (using "handleLease") did not return any output, we couldn’t pinpoint the exact implementation details. Additional manual verification is needed to confirm whether the server implementation is intentionally returning 202. Once verified, update the test expectation accordingly.

Action items:

  • Verify with the implementation whether a cache hit with an “accepted” status should return 202.
  • If 202 is correct, update the test diff from:
     - expectedStatus: http.StatusCreated,
     + expectedStatus: http.StatusAccepted,
  • Confirm that this update is consistent with your overall API behavior for accepted leases.
internal/application/application_test.go (2)

98-101: LGTM! Proper error test case for lease revival.

The test correctly checks the error case for lease ID 999, which corresponds to the mock implementation in KeepLeaseOnce.


123-155: LGTM! Great concurrent testing approach.

The concurrent test case properly validates both lease creation and revival operations running simultaneously, which is important for verifying thread safety.

return
}

if s.app.LeaseCache != nil {
Copy link

Choose a reason for hiding this comment

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

необхідно перенести це в середину application (це не на рівні контролера логіка), контролер не має знати про LeaseCache

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Заніс в application

return
}

if s.app.LeaseCache != nil {
Copy link

Choose a reason for hiding this comment

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

необхідно перенести це в середину application (це не на рівні контролера логіка), контролер не має знати про LeaseCache

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Заніс в application

LeaseCache *cache.Cache
Ctx context.Context
Config *config.Config
LeaseCache *cache.Cache
Copy link

Choose a reason for hiding this comment

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

є сенс робити все private щоб ззовні від application не було операцій з атрибутами та деталями реалізації application

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Зробив усе приватним

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
internal/delivery/http/server.go (2)

60-106: 🛠️ Refactor suggestion

Improve error handling in lease creation.

The error handling for the lease creation is incomplete. When an error occurs during lease creation, you set the status code to 500 but don't provide an error message, making it harder to debug issues.

Apply this diff to improve error handling:

  leaseStatus, leaseID, err = s.app.CreateLease(leaseTTL, lease)
  if err != nil {
-    w.WriteHeader(http.StatusInternalServerError)
+    log.Errorf("Failed to create lease: %v", err)
+    http.Error(w, fmt.Sprintf("Failed to create lease: %v", err), http.StatusInternalServerError)
    return
  }

148-152: ⚠️ Potential issue

Fix status code for lease revival failure.

When reviving a lease fails, you're returning HTTP 204 (No Content) which indicates success with no content. This is misleading for clients as they'll think the operation succeeded.

Apply this diff to fix the issue:

  err = s.app.ReviveLease(leaseID)
  if err != nil {
    log.Warnf("Failed to prolong lease: %v", err)
-   http.Error(w, "Failed to prolong lease", http.StatusNoContent)
+   http.Error(w, "Failed to prolong lease", http.StatusInternalServerError)
    return
  }
🧹 Nitpick comments (5)
README.md (3)

30-30: New Environment Variable for pprof Debugging
The addition of SHARED_LOCK_PPROF_ENABLED with a default value of false is clear and beneficial for toggling pprof-based debugging. Make sure that if enabled in production, proper security precautions are in place.


32-32: Updated etcd Address Format
Changing the default for SHARED_LOCK_ETCD_ADDR_LIST from localhost:2379 to http://localhost:2379 clarifies the required protocol. Note that markdownlint may flag this as a bare URL (MD034); you might consider formatting it as inline code (e.g., `http://localhost:2379`) for consistency.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

32-32: Bare URL used
null

(MD034, no-bare-urls)


38-38: New Environment Variable for Cache Size Limit
Adding SHARED_LOCK_CACHE_SIZE with a default value of 1000 provides configurability for cache capacity. This is a useful feature to help manage memory usage. Verify that the default value offers a good balance between performance and resource utilization.

internal/delivery/http/server.go (2)

11-11: Consider explicitly using pprof handlers.

The blank import for pprof registers handlers with the default ServeMux, but it's generally better to explicitly register the handlers you need for better control and clarity.

Instead of the blank import, consider explicitly importing and registering specific pprof handlers:

-import (
-	_ "net/http/pprof"
-)

+import (
+	"net/http/pprof"
+)

// Then in your Start method:
+	if cfg.PPROFEnabled {
+		mux.HandleFunc("/debug/pprof/", pprof.Index)
+		mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
+		mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
+		mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
+		mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
+	}

111-124: Consider validating leaseID before writing response.

For non-error cases, the code writes the leaseID to the response without checking if it's valid (could be 0 for accepted leases). You might want to include additional context or validation.

Consider adding more context or a check:

  switch leaseStatus {
  case storage.StatusAccepted:
    w.WriteHeader(http.StatusAccepted)
  case storage.StatusCreated:
    w.WriteHeader(http.StatusCreated)
  default:
    w.WriteHeader(http.StatusInternalServerError)
  }

+ // For accepted leases, leaseID will be 0
+ responseBody := fmt.Sprintf("%v", leaseID)
+ if leaseStatus == storage.StatusAccepted {
+   responseBody = "Lease already exists"
+ }

- _, err = w.Write([]byte(fmt.Sprintf("%v", leaseID)))
+ _, err = w.Write([]byte(responseBody))
  if err != nil {
    log.Errorf("Failed to write response for /lease endpoint, %v", err)
    return
  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f9239c and 5c3ca9e.

📒 Files selected for processing (4)
  • README.md (1 hunks)
  • internal/application/application.go (1 hunks)
  • internal/config/config.go (3 hunks)
  • internal/delivery/http/server.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/config/config.go
🧰 Additional context used
🧬 Code Graph Analysis (2)
internal/delivery/http/server.go (4)
internal/infrastructure/metrics/metrics.go (2)
  • LeaseOperationDuration (21-28)
  • LeaseOperationGet (9-9)
example/client.go (1)
  • Lease (21-26)
internal/application/command/leasemanagement/leaseManagement.go (2)
  • CreateLease (17-47)
  • ReviveLease (49-56)
internal/infrastructure/storage/storage.go (2)
  • StatusAccepted (8-8)
  • StatusCreated (9-9)
internal/application/application.go (4)
internal/infrastructure/cache/cache.go (3)
  • Cache (11-17)
  • New (34-45)
  • LeaseCacheRecord (29-32)
internal/infrastructure/storage/storage.go (1)
  • Storage (12-16)
internal/application/command/leasemanagement/leaseManagement.go (2)
  • CreateLease (17-47)
  • ReviveLease (49-56)
internal/infrastructure/metrics/metrics.go (2)
  • LeaseOperations (13-19)
  • CacheOperations (30-36)
🪛 markdownlint-cli2 (0.17.2)
README.md

32-32: Bare URL used
null

(MD034, no-bare-urls)

🔇 Additional comments (11)
README.md (2)

31-31: New Environment Variable for Storage Type Selection
SHARED_LOCK_STORAGE_TYPE has been added to allow users to specify the storage mechanism (either etcd or mock). The description is concise and informative. Consider providing an example in the documentation if users might be unfamiliar with the options.


37-37: New Environment Variable to Enable Cache
The introduction of SHARED_LOCK_CACHE_ENABLED clearly indicates the option to use an in-memory cache for leases. This aligns with the objective of optimizing memory consumption. The documentation is straightforward.

internal/application/application.go (6)

16-19: Field naming follows encapsulation principles.

The change from exported (capitalized) field names to unexported (lowercase) field names is a good practice. This aligns with the principle of encapsulation, keeping the internal details of the Application struct private and preventing external manipulation.


22-28: Storage connection integration looks good.

Adding the storage connection as a parameter to the constructor and storing it in the struct is a good approach. This allows the application to manage a single storage connection instance, which should help reduce memory consumption as mentioned in the PR objectives.


31-45: New CreateLease method handles delegation well.

The implementation correctly delegates to the leasemanagement.CreateLease function, properly handles errors, and updates metrics appropriately. This encapsulation of lease creation logic within the application layer is a good design choice.


47-57: ReviveLease method implementation is correct.

The method properly delegates to the appropriate leasemanagement function and handles error cases correctly with appropriate metrics tracking.


59-69: Cache presence check handles edge cases.

The method correctly handles the case where the cache is nil, which is a good defensive programming practice.


84-93: AddLeaseToCache method implementation is correct.

The method properly handles the nil cache case and correctly sets the cache entry with the appropriate TTL.

internal/delivery/http/server.go (3)

22-25: Good use of constants for configuration values.

Defining constants for headers and default durations improves code maintainability and readability.


45-47: PPROF handler registration looks good.

The conditional registration of the pprof handler based on the configuration flag is a good practice.


155-157: Simplified health endpoint looks good.

The simplified health endpoint is cleaner and more straightforward.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
internal/application/application.go (1)

59-69: Cache presence check handles nil cache properly.

The method correctly checks for lease presence in the cache and handles the case where the cache might be nil. However, the error return value seems unnecessary since no error conditions are actually being returned.

Consider simplifying the method signature to just return a boolean since no error conditions are being returned:

-func (a *Application) CheckLeasePresenceInCache(key string) (bool, error) {
+func (a *Application) CheckLeasePresenceInCache(key string) bool {
   if a.leaseCache == nil {
-    return false, nil
+    return false
   }

   if _, exists := a.leaseCache.Get(key); exists {
-    return true, nil
+    return true
   }

-  return false, nil
+  return false
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f85288b and 69f2669.

📒 Files selected for processing (1)
  • internal/application/application.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
internal/application/application.go (3)
internal/infrastructure/cache/cache.go (2)
  • Cache (11-17)
  • LeaseCacheRecord (29-32)
internal/infrastructure/storage/storage.go (1)
  • Storage (12-16)
internal/application/command/leasemanagement/leaseManagement.go (2)
  • CreateLease (17-47)
  • ReviveLease (49-56)
🔇 Additional comments (6)
internal/application/application.go (6)

16-19: Appropriate naming convention change to private fields.

The fields have been renamed from PascalCase to camelCase, making them private as suggested in the previous review. This change properly encapsulates the internal implementation details of the Application struct.


22-28: Good integration of storage connection into the Application struct.

The constructor now accepts a storage connection parameter, which aligns with the PR objective to use a common connection to reduce memory consumption. The initialization of all fields follows a consistent pattern.


31-45: Well-implemented lease creation with proper error handling.

The CreateLease method correctly delegates to leasemanagement.CreateLease using the application's storage connection. The error handling, metrics collection, and return values are appropriately managed.


47-57: Proper implementation of lease revival functionality.

The ReviveLease method correctly delegates to leasemanagement.ReviveLease and includes appropriate error handling and metrics collection.


71-82: Fixed logging placement in GetLeaseFromCache.

The debug log and metrics increment are now correctly placed before the return statement, fixing the issue mentioned in the previous review where they were unreachable when a cache hit occurred.


84-93: Cache addition handles nil cache properly.

The method correctly adds a lease to the cache with the specified parameters and handles the case where the cache might be nil. The implementation is clean and straightforward.

@vpapidokha vpapidokha merged commit 43ca4bb into main Apr 14, 2025
3 checks passed
@vpapidokha vpapidokha deleted the reduce-mem-consumption branch April 14, 2025 08:33
This was referenced Apr 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants