Skip to main content

· 2 min read
Ragavendra Nagraj

In this article, I will demonstrate on how one can add additional methods to existing struct types like int, string, char, long, etc,.

This can be beneficial when the existing methods for that type is like not handful for a certain situation say like reversing a string. Some of existing method say for string type includes .ToUpper(), .ToLower(), .Trim() and so on.

Let us call our new method Reverse().

First we need to have static class for it and static method like below.


public static class AfceClass

{

public static string Reverse(this string theStr)
{

string theStrNew;

foreach(char ch in theStr)
{

thStrNew =+ ChangeCase(ch) ;

}

return thStrNew;

}


public static string ChangeCase(char chr)

{

// steps to change or negate the char case
return chr.toUpper();

}

}

Note, the use of the this keyword to the parameters which more or less makes the method chain.

Now, if you find any variables of type string, it should also have the Reverse() method as well and documentation if added in the comments for that method.

Extension method can be used of types other than struct or for user defined types as well. One aspect is the static class should not be nested in the same class where one is using it as well.

Sample using the generic type


public static class AfceClass

{

public static E NewExtMethod<E, T>(this T theStr)
{

E theStrNew;

....

...

...

return thStrNew;

}

}

Now with Generics, the NewExtMethod<E, T> should populate with any types but make sure to pass the E and T types.

This can be further refined to be populated with only certain types with the where clause like below.


public static class AfceClass

{

public static E NewExtMethod<E, T>(this T theStr) where T : long, int where E : long
{

E theStrNew;

....

...

...

return thStrNew;

}

}

Usage - One can use this to have like a common method say like add leading zeros to an int or a long and return as a string or even use as user types with much more options.

· 2 min read
Ragavendra Nagraj

C# introduces the ?? and ??= operators which are known as the Null coalescence operators.

Purpose - The ?? and ??= operators can help in cases where a comparison is made between two or more variable values and depending on the order in the statement, the variable valu is used.

Say for example there is variable either a and b to be returned by a method. Say if value is needed to be returned if it is not null and if yes, the value b is supposed to be returned.

public class NullCoal
{
public static int? Method(int? input)
{
....
....
int? a;
int? b;


if(input > 10)
{
a = input * 6;
}
else
{
b = input * 7:;
}

return a ?? b;
}
}

In the above example, a is returned if it is not null or b is returned.

Similarly the ??= operator adds the assignment operation as well, which can be used like

    int? a = null;
int? b = 1;

a ??= b;

where if a is not null, value of b is assigned to it, otherwise nothing happens with the above statement.

The null coalescence operator is a short form for writing the below code.

if( a is null)
{
a = 1;
}

instead it can be written as

a ??= 1;

What if there is more than two variables to check, in such cases say like below

return a ?? b ?? c;

the expression is evaluated from right to left like this

return a ?? ( b ?? c)

· 6 min read
Ragavendra Nagraj
Ankitha

Service to enable load testing on different types of network calls.

Welcome to the PerfService wiki!

PerfService is a whole suite of dotnet projects to run performance test(s)

a. PerfRunner b. PerfLoader c. PerfRunnerTests

under one repository.

PerfRunner

The actual hoster and runner of service which has a folder called tests which contain the tests. Simply copy the TestBase.cs in it to your new test and update the RunTest method in it to suit your performance test needs. The http client has been typed DIed into _httpClient which can be used in the test(s) to make the http calls along with an end point.

To run on a specific port, when running multiple instances.

dotnet run --no-build Debug urls=http://0.0.0.0:5278

PS - Need to update docker-compose.yml for more than one PerfRunner

PerfLoader

Front end or the web interface to initiate performance test run(s) and control or to stop them. Screen

PerfRunnerTests

Unit tests for the PerfRunner to be kept updated with any new features added to the PerfRunner project.

Architecture

Architecture

Getting Started

Docker

Once in this directory. Should be as straight as

sudo docker build -t perfrunner .

and

docker compose up --no-build

The mcr.microsoft.com/dotnet/sdk:6.0 and redis:alpine images are used.

Redis Cache manager

Redis is used as a common user store to store users and are pulled and pushed into a queue there say when one or multiple PerfRunners are running.

PerfRunner can alone be run without the redis as well, in which case the user store should default to the in-memory queue and running multiple Perfrunners can cause the same user to call the api's from each of the PerfRunners.

Planned features

....

Existing features

  1. Abitlity to create and run http test(s).
  2. UI to run, view and stop test(s).
  3. Ability to update rate per sec during test run.
  4. Abitlity to create and run gRPC test(s).
  5. Account data support with User object having state has well. Each user have their own state and are in the queue per state and updated by the test(s) accordingly.
  6. User state management - as user queue per each state.
  7. Ability to transfer data across test(s) - can be achieved by adding new data properties to the User object itself, say like the phone number, library card number, health number and so on. This is updated and be used by each test(s) accordingly by dequeing that state queue with the user with that updated data. Say the user just registeted at the front desk with payment, library no, his state is now authenticated and library no. is the new data and he is in the authenticated state queue. Whenever its his turn, that user gets popped from that queue.
  8. Support for flag for even or uneven load distribution per second. 8a. If each action has a rate that is used for rate otherwise default to test rate.
  9. Try using interface inherit implementation.
  10. Monitor traffic in prometheus or Grafana cloud. Check the Grafana dashboard json to import it to the Grafana dashboard.
  11. Update rate for individual action.
  12. Pause/ Unpause individual action.
  13. Set duration for action and test. Whichever comes first will stop first.
  14. Updating duration for action will run the action for the next n update seconds since update.
  15. Update distribution for each action.
  16. Run, update and monitor test(s) on selected runner(s). If no runner is selected, all are probed*.
  17. PerfLoader dynamically maintains the PerfRunner(s) list using Polly polling every minute.

Planned features - Loader

  1. Clean front end interface for interaction. The app needs a lot of fron end improvement yet. Basic operations such as rate, duration and distribution updates are instantanious.

Sample Web app

For this use case, I am using the Bowling alley web app, assuming when a user goes to the ally, he has to say, get autheneticated, next wait for the lane and if lane is available, play can be initiated. For each stage, state can be represented, which is defined in UserState.

Monitoring

There are several ways to monitor like below.

CLI

The easiest way is with dotnet-counters. You can observe the distribution when you flip from Even to Uneven or vice - versa.

dotnet-counters monitor -n PerfRunner --counters PerfService.PerfRunner

Prometheus

Prometheus is used to more or less display or relay the instrumentation metrics to apps like Grafana or similar. To install you may have to download and run it on your distribution. The config file for it is here or append the scrape config like below.

  - job_name: 'PerfRunner'
scrape_interval: 1s # poll very quickly for a more responsive demo
static_configs:
- targets: ['localhost:9186']

Grafana

To run Grafana as a docker image, run.

docker run -d --name=grafana -p 3000:3000 grafana/grafana-enterprise
admin

Run results

Please refer here for a sample run with upto 300 users per second with 12 core processor and having about 17% CPU usage and about 1.5 GB memory usage.

Sample commands

To run from tests directly CLI with PerfRunner running.

$ grpcurl -plaintext localhost:5277 describe
perf.Perf is a service:
service Perf {
rpc Ping ( .perf.PingRequest ) returns ( .perf.PingReply );
rpc RunTest ( .perf.TestRequest ) returns ( .perf.TestReply );
rpc StopAllTests ( .perf.StopAllTestsRequest ) returns ( .perf.StopAllTestsReply );
rpc StopTest ( .perf.StopTestRequest ) returns ( .perf.StopTestReply );
rpc UpdateRate ( .perf.UpdateRateRequest ) returns ( .perf.UpdateRateReply );
}
grpc.reflection.v1alpha.ServerReflection is a service:
service ServerReflection {
rpc ServerReflectionInfo ( stream .grpc.reflection.v1alpha.ServerReflectionRequest ) returns ( stream .grpc.reflection.v1alpha.ServerReflectionResponse );
}
$ grpcurl -plaintext localhost:5277 describe perf.TestRequest
perf.TestRequest is a message:
message TestRequest {
string guid = 1;
string name = 2;
int32 rate = 3;
repeated .perf.ActionOption actions = 4;
}

License

Free for non-commercial use, but please read LICENSE for commercial use, other(s) and support.

Issues

Please report any issues here. This can be ranging from a minor defect to a valid feature request.

Contribution

If you would like to contribute to thie repository, please read CONTRIBUTING before creating your PR.

Customizations/ Support

G Sys

Donations

If you like using this repository and like to donate, please visit the below link. This work is made possible with donations like yours. PM for customizations and implementations .

paypal

· 3 min read
Ragavendra Nagraj

In this article I will try to give some overview about why and when to use Rabbit Message Queue and Redis cache. Starting with Redis cache

Redis cache -

  1. Mainly used for caching as call time to server ( say database server ) can delay. Using redis cache saves this time, as it is the cache of the database itself. Whenever a database write has happened, a worker class can update the cache to be in sync with the database.
  2. Key value pair type of database supporting strings, int, lists, hash as values.
  3. The list can used as stacks or queues and other data structures as well like linked list, circular queue and all.
  4. Remember, the key has to be in lower case.
  5. Redis say instead of sending many continuous updates in subsequent calls, these can be piped and send as a single call.
  6. Calls can be direct or pub - sub type
  7. StackExchange.Redis is a popular nuget package to perform almost all the database operations in the redis documentation.
  8. redis - cli can be used locally to connect to the database and perform CRUD operations. Convenience of using regex in calls to retrieve data fastly.

Rabbit Message Queue ( RMQ ) -

  1. Queue or many queues behind an exchange.
  2. The exchange does the routing to the particular queue based on the header information.
  3. Data in a queue can be set to be durable, meaning data is not lost after RMQ is re started. For docker containers make sure to use common volumes across container restart(s).
  4. Data in a durable queue can stay from two to three days.
  5. MassTransit is one nuget package which can be used with different types of Enterprise service bus like RMQ, Azure queue, AWS queue, in memory queue and all without needing to write the adapters for each.
  6. When a message is sent to a RMQ it first goes to the exchange and the exchange routes that message to its queue.
  7. Used mainly for mass data transfers and Mass transit client consumes it almost in no time.
  8. The main reason to use Enterprise service bus is to ensure reliability of the message sent. The recipient server may be busy with some operation(s) unable to provide cycles or bandwidth to consume the incoming messages from the client. These messages can be lost if not addressed in a timely manner, thereby giving poor experience to its caller. Supports direct messaging to the recipient or publish subscriber mechanism where the Consumer is listening to the queue(s) in the RMQ for any new messages.

Writing Consumer in Mass transit should be as straight forward as implementing the IConsumer type and having a task named Consume with ConsumerContext parameter like below.

public class AfceConsumer :
IConsumer<AfceMessage>
{

public Task Consume(ConsumeContext context)
{
Console.WriteLine("Hello {name}", context.Message.Title);
return Task.CompletedTask;
}
}

The above consumer will continuously consume each message one by one in almost no time when the message of type AfceMessage is available in the queue. The AfceMessage can be any reference type like a class or a record or a struct.

Mass transit also has bulk message consumer to consume message in batches.

· One min read
Ankitha
Ragavendra Nagraj

Docusaurus blogging features are powered by the blog plugin.

Simply add Markdown files (or folders) to the blog directory.

Regular blog authors can be added to authors.yml.

The blog post date can be extracted from filenames, such as:

  • 2019-05-30-welcome.md
  • 2019-05-30-welcome/index.md

A blog post folder can be convenient to co-locate blog post images:

Docusaurus Plushie

The blog supports tags as well!

And if you don't want a blog: just delete this directory, and use blog: false in your Docusaurus config.

· One min read
Gao Wei

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet