Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
RafaelJCamara committed Jun 29, 2023
2 parents 04db0f6 + 76116e2 commit 1f3bb62
Show file tree
Hide file tree
Showing 30 changed files with 866 additions and 18 deletions.
7 changes: 7 additions & 0 deletions Nebula.Caching.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebula.Caching.Common", "sr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebula.Caching.Redis", "src\Nebula.Caching.Redis\Nebula.Caching.Redis.csproj", "{847F1E55-A4CF-4633-A322-9B08DADE7B30}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nebula.Caching.InMemory", "src\Nebula.Caching.InMemory\Nebula.Caching.InMemory.csproj", "{D77EA6CF-7825-458A-B32E-D7481644627D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -26,9 +28,14 @@ Global
{847F1E55-A4CF-4633-A322-9B08DADE7B30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{847F1E55-A4CF-4633-A322-9B08DADE7B30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{847F1E55-A4CF-4633-A322-9B08DADE7B30}.Release|Any CPU.Build.0 = Release|Any CPU
{D77EA6CF-7825-458A-B32E-D7481644627D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D77EA6CF-7825-458A-B32E-D7481644627D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D77EA6CF-7825-458A-B32E-D7481644627D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D77EA6CF-7825-458A-B32E-D7481644627D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{DDB9C8EA-96AA-4EAE-AF56-7B4897CA4EE7} = {F0265230-4219-46CB-8FCC-A946BC6447CA}
{847F1E55-A4CF-4633-A322-9B08DADE7B30} = {F0265230-4219-46CB-8FCC-A946BC6447CA}
{D77EA6CF-7825-458A-B32E-D7481644627D} = {F0265230-4219-46CB-8FCC-A946BC6447CA}
EndGlobalSection
EndGlobal
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@ As of today, we support caching using Redis and InMemory, but in the future we h

## Nuget Package

| Name | Released Package |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Nebula-Caching-Redis | [![BotBuilder Badge](https://buildstats.info/nuget/Nebula-Caching-Redis?includePreReleases=true&dWidth=70)](https://www.nuget.org/packages/Nebula-Caching-Redis/) |
| Name | Released Package |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Nebula-Caching-Redis | [![BotBuilder Badge](https://buildstats.info/nuget/Nebula-Caching-Redis?includePreReleases=true&dWidth=70)](https://www.nuget.org/packages/Nebula-Caching-Redis/) |
| Nebula-Caching-InMemory | [![BotBuilder Badge](https://buildstats.info/nuget/Nebula-Caching-InMemory?includePreReleases=true&dWidth=70)](https://www.nuget.org/packages/Nebula-Caching-InMemory/) |

## Usage

### Step 1 : Install the package
### Step 1 : Install one of the available packages

Install the package via Package Manager:

```
Install-Package Nebula-Caching-Redis
Install-Package Nebula-Caching-InMemory
```

or
Expand All @@ -33,9 +35,10 @@ Via .NET CLI:

```
dotnet add package Nebula-Caching-Redis
dotnet add package Nebula-Caching-InMemory
```

### Step 2 : Register cache usage in the Program class
### Step 2 : Register cache usage in the Program class (will change depending on which caching provider you are using, please refer to the package documentation)

```csharp

Expand All @@ -55,7 +58,7 @@ public class Program

```

### Step 3 : Use the caching attribute in your interface definitions
### Step 3 : Use the caching attribute in your interface definitions (will change depending on which caching provider you are using, please refer to the package documentation)

```csharp

Expand All @@ -69,11 +72,11 @@ public class Program

## Documentation

Our documentation can be found [here](docs/documentation/Docs.md).
Our documentation can be found [here](docs/documentation/).

## Samples

Some useful code snippets can be found [here](docs/samples/Samples.md).
Some useful code snippets can be found [here](docs/samples/).

## CI Status

Expand Down
164 changes: 164 additions & 0 deletions docs/documentation/InMemory/AttributeUsage/AttributeUsage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Using the caching attribute

The attribute that is going to be used is called InMemoryCache.

As of today, we are limited to using this attribute only in interface definition.

An example is shown below.

```csharp

public interface IInMemoryStuff
{
[InMemoryCache]
List<SomeObject> SomeMethod(int param1, int param2, string name);

[InMemoryCache]
Task<List<SomeObject>> AnotherMethod();
}

```

## Cache Duration

There are several ways to set your cache duration.

### Cache duration from attribute

The easiest way to set the cache duration is by declaring it directly on the interface definition, using the _CacheDurationInSeconds_ property.

```csharp

public interface IInMemoryStuff
{
[InMemoryCache(CacheDurationInSeconds = 120)]
List<SomeObject> SomeMethod(int param1, int param2, string name);

[InMemoryCache(CacheDurationInSeconds = 272)]
Task<List<SomeObject>> AnotherMethod();
}

```

Keep in mind the _CacheDurationInSeconds_ accepts cache durations in seconds.

If no value is inserted, like the first example, the default cache duration will be applied (which is 600 seconds).

### Cache duration from cache registration

If you want to use another default value for your cache duration, you can do so while registring the cache.

Please check [this](../CacheRegistration/CacheRegistration.md) for more information on how to do so.

### Cache duration from configuration file

In an effort to make our interfaces more clean while still using custom cache duration, you can leave your cache attribute definition without specifying the cache duration, but that same cache duration comes from a configuration section of _appsettings.json_.

When configuring your [cache usage](../CacheRegistration/CacheRegistration.md), you can specify a specific section from your _appsettings.json_ file where you are going to read all your cache configurations from. By default, the section name is **_InMemory_**.

Under the section you defined above, create a new section called _CacheSettings_, where you are going to place the your cache duration.

The key you need to use here should the a template key based upon the namespace your interface implementation lives upon. For more information on what to place on the key part, please refer to [this](../CacheKeyGeneration/CacheKeyGeneration.md).

The value for your cache duration should follow the _HH:MM:SS_ pattern, where HH represents Hours, MM represents Minutes and SS represent seconds. So, for example, if you want your cache to have a duration of 1 hour, 15 minutes and 30 seconds, the value should for the duration should be _01:15:30_.

Below you can find an example of how this could exist in your configuration:

```json
"InMemory": {
"CacheSettings": {
"Gorold-Payment-Attributes-InMemoryStuff--AnotherMethod": "01:15:30",
"Gorold-Payment-Attributes-InMemoryStuff--SomeMethod--{param1}--{param2}--{name}": "00:20:00"
}
}
```

Let's take a closer look at the structure of the second configuration cache key (same conclusions apply for any kind of key to be inserted).

```
//this is the key we are analyzing
Gorold-Payment-Attributes-InMemoryStuff--SomeMethod--{param1}--{param2}--{name}
Gorold-Payment-Attributes-InMemoryStuff -> Namespace where the interface, where the attribute was placed, implementation is located. Notice that we replaced all the '.' for '-'.
--SomeMethod--{param1}--{param2}--{name} -> The remaining part of the key is constitued of the method where the attribute was placed, plus the methods it might contain. If no parameters exist, then we don't need to insert them on the cache key definition. If you notice closely, when you are adding cache duration for methods that take parameters, you must add such parameters inside the curly braces. You should add only the parameter name, not its value. Also notice that, unline above, we use double '-' to separate things.
```

### Hierarchy in cache duration definition

One might ask what happens if I define the cache duration inline, meaning in the interface definition, and also in the _appsettings.json_ file.

As of today, the cache defined in the configuration file will be taken in consideration in this conflict scenario.

So, this are the cache values taken:

1. **_Cache defined both in the configuration file and in the interface method_**: value defined in the configuration file taken
2. **_Cache only defined in the configuration file_**: value defined taken as the cache duration
3. **_Cache only defined in the interface method_**: value defined taken as the cache duration
4. **_Cache not defined in the configuration file nor in the interface method_**: default value for cache duration taken

## Cache Groups

Sometimes you may have the need to give a group of caches the same duration, because there might be some logical grouping that you want to have. For this case, we have created cache groups.

Cache groups allow you to specify, in your attribute definition, the cache group it belongs. That is done via the _CacheGroup_ property. There must be a corresponding configuration section under your cache root configuration section (as we saw before, _InMemory_ was the default for that) that indicates the duration for that cache group; that should be in a section called _CacheGroupSettings_ under your root one. The duration time specificied should follow the pattern spoken about earlier, meaning following the _HH:MM:SS_ pattern

Below you can find an example of cache groups in pratice, which puts the cache created on the method _SomeMethod_ inside a cache group called _GroupA_ and, according to this group's cache configuration, the cache will have a duration of 2 hours 23 minutes and 15 seconds.

### Interface definition of cache group

```csharp

public interface InMemoryStuff
{
[InMemory(CacheGroup = "GroupA")]
List<SomeObject> SomeMethod(int param1, int param2, string name);
}

```

### Configuration definition of cache group

```json
"InMemory": {
"CacheGroupSettings": {
"GroupA" : "02:23:15"
}
}
```

## Custom Key Names

Traditionally, you want to use the automatically generated cache keys, because they are designed so that no collisions occur. The way we generate keys is also helpful because they indicate from which method you are caching data from, which can be very helpful.

Despite the advantages of using our generated cache keys, you might want to set your cache keys with custom names which might be better for your, mainly because you might understand them better.

To fulfill that need, we introduced a property in our attribute definition called _**CustomCacheName**_.

An example of that can be seen below:

### Interface definition of custom cache name

```csharp

public interface IInMemoryStuff
{
[InMemory(CustomCacheName = "MyCustomCacheName")]
List<SomeObject> SomeMethod(int param1, int param2, string name);
}

```

### Configuration definition of our cache duration based on our custom cache key name

```json
"InMemory": {
"CacheGroupSettings": {
"MyCustomCacheName" : "04:00:00"
}
}
```

> :warning: Please note that, if you choose to have a custom cache key name, if you want to use the configurations to specify the cache duration, you need to place the custom cache name chosen, and not the default generated one.
> :warning: When choosing your custom cache names, you must manage key collision, meaning choosing unique custom cache keys, otherwise you will have unwanted behavior in your application.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# How keys are generated for our cache

As we have [discussed](../CacheKeyGeneration/CacheKeyGeneration.md) before, we must place our cache attribute on the interface method(s) that we are interested in caching, and all of this action happens on the interface itself.

Cache keys, however, are generated based upon the namespace on which such interface is implemented.

Let's say our interface is:

```csharp
namespace Gorold.Payment.Attributes
{
public interface IInMemoryStuff
{
[InMemoryCache]
List<SomeObject> SomeMethod(int param1, int param2, string name);
}
}
```

And the implementation lives on:

```csharp
namespace Gorold.Payment.Attributes
{
public class InMemoryStuff : IInMemoryStuff
{
public List<SomeObject> SomeMethod(int param1, int param2, string name)
{
var list = new List<SomeObject>(){new SomeObject
{
Name = name,
Value1 = param1,
Value2 = param2
}, new SomeObject
{
Name = name,
Value1 = param2,
Value2 = param1
}};
return list;
}
}
}
```

The cache key generation formula is:

```
namespace.separated.by.dot.with.class.name:method:parameters:separed:by:colon
```

So if we call the method with

- param1 = 10
- param2 = 20
- name = Rafael

We should expect our cache key to be:

- Gorold.Payment.Attributes.InMemoryStuff:SomeMethod:10:20:Rafael

As you can see, there are two parts you can easily identity: one which is separated by dot (.) and another that is separated by colon (:).

The first section, that is separated by dot (.), corresponds to the namespace until the method we placed the attribute (excluding it).

The second section, that is separated by colon (:), corresponds to the method where the cache attribute has been placed, alongside the values of the attributes that were passed to such method. If no parameters were passed, the cache key would end at _:SomeMethod_.
61 changes: 61 additions & 0 deletions docs/documentation/InMemory/CacheRegistration/CacheRegistration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Registring the cache usage

As mentioned in the [README](../../../../README.md), the first step to start using out our cache is to register the cache usage inside the _Program.cs_ class:

```csharp

public class Program
{
public static void Main(string[] args)
{
// ...
builder.Host.UseNebulaCaching();
builder.Services.AddInMemoryChache(new Configurations
{
//some amazing optional configuration options
});
}
}

```

As mentioned above, in the _AddInMemoryChache_ method, there are some configuration options we can use when registering our cache.

The following options are, as of today, supported:

## ConfigurationSection

String that represents the section in your _appsettings.json_ where the cache configuration will be placed. By default the value here is **_"InMemory"_**.Example of configurations placed in such section may include the cache duration for your keys (if you end up choosing this path). Please refer to [this](../AttributeUsage/AttributeUsage.md) for more information on cache duration options.

## DefaultCacheDurationInSeconds

Sometimes we don't want to have the hassle to define cache values for each method, and instead just use a pre-defined cache duration value.

If you think the current default value for the cache duration doesn't suit you well (600 seconds), then you have the opportunity to override it by making use of the _DefaultCacheDurationInSeconds_ in the _Configurations_ object.

Insert the int value that represents the new default cache duration, in seconds.

Again, please refer to [this](../AttributeUsage/AttributeUsage.md) for more information on other ways to set the cache duration.

## Example of a cache registration

Below you can find an example of what the cache registration could look like in your _Program.cs_ class, having all we discussed in consideration:

```csharp

public class Program
{
public static void Main(string[] args)
{
// ...
builder.Host.UseNebulaCaching();
builder.Services.AddInMemoryChache(new InMemoryConfigurations
{
ConfigurationSection = "InMemoryConfig",
DefaultCacheDurationInSeconds = 120
});
}
}

```
13 changes: 13 additions & 0 deletions docs/documentation/InMemory/Docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Documentation entry point

## Registring the cache usage

For a more in-depth understading of the cache registration process, please refer to [this](CacheRegistration/CacheRegistration.md).

## Using the caching attribute

For a more in-depth understading on the usage of of the caching attribute, please refer to [this](AttributeUsage/AttributeUsage.md).

## Memory considerations

For some concerns regarding memory considerations, please refer to [this](MemoryConsiderations/MemoryConsiderations.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
As you might already know, there's a limit on the amount of memory available on the machine that is running your .NET applicaton, so you must be very careful when taking the decision of taking a portion of that memory for caching purposes.

Because of the constraint presented above, our in-memory solution uses a compression algorithm when storing your cached data. Of course, this comes with the cost of running the compression algorithm (and the decompression one when retrieving the cached data), but that's a worthwhile cost to pay.
Loading

0 comments on commit 1f3bb62

Please sign in to comment.