Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Core): CNX-8352 operations.send #3094

Merged
merged 6 commits into from
Dec 12, 2023
Merged

Conversation

JR-Morgan
Copy link
Member

As part of our effort to reduce analyser warnings across our code base. It's important that our Core functions are clear about what exceptions types they throw.

This motivation for this PR was to focus on Operations.Send and attempt to enforce and provide clear guidance on the exception types that can be thrown.

Our original Operations.Send overloads were doing some smelly things:

In the signature of the function alone:

  1. We were allowing users to pass in a SerializerVerion enum to switch to using the old v1 serializer. This serializer hasn't been used (or tested) in almost two years, its past time we drop exposing it as an option for Operations.Send
  2. A long time ago, we were using OnErrorAction to signal errors in transports and sending. We have since deprecated this in favour of throwing proper Exceptions instead. This property is effectively unused with our current Operations.Send
  3. We were exposing a disposeTransports boolean (defaulting to false) that, when true, we would loop through and dispose any IDisposable transports that the user passes through. This doesn't follow any normal C# guidance on how IDisposables should be handled, and on top of that, we weren't disposing inside a finally block, so if an exception did occur, we weren't disposing the transports anyway. Thus this "feature" was not really usable, and much cleaner solved by expecting caller to handle the disposal using e.g. using a using keyword.

And in the implementation:

  1. We were performing input validation, logging, timers, error handling, SQLite setup, transport manipulation + extra nonsense for serailizer v1, as well as performing the actual send!

In my new implementation, we have far fewer parameters, removing the obsolete and questionable designed ones.
We have also separated logging and error handing into one function SendToTransports and the actual send logic in an internal SendInternal function.

* ci: Show all warnings on CI builds

* fix(all): Do not allow IDE0005 on CI

* fix(sdk): IDE0005 Redundant Using statements in SDK projects (#3071)

* fix(core): IDE0005 Redundant Using statements

* fix(ci): GenerateDocumentationFile is required for IDE0005 to run on CI

* fix(ci): Allow warnings on all CI jobs

* fix(rhino/grasshopper): Fix IDE0005 Redundant Using Statements  (#3072)

* fix(gh): IDE0005 for Grasshopper connector

* fix(rhino): IDE0005 for Rhino connector

* fix(rh/gh): IDE0005 for Rhino/Grasshopper shared converter

* tamed some warnings

* Hushed more warnings

* Eliminated many warnings in core

* More fixes for Alan

* Core fix

* More changes

* Base object serializer

* fixed erroneous disposal

* Reverted accidental change to blob constructor accessiblity

* reverted switch needless statement change

* Reverted some extra changes that weren't meant to be made

* Supressed some extra resharper analysers

* Deprecated serailizer v1 for sending

* Deprecated send using v1 deserailize and offered cleaner overloads to send function

* unnecessary using directive

* fixed issue with checking struct for null

---------

Co-authored-by: Alan Rynne <alan@speckle.systems>
@JR-Morgan JR-Morgan changed the base branch from main to dev December 4, 2023 12:54
Core/Core/Models/Base.cs Outdated Show resolved Hide resolved
/// </example>
public static async Task<string> Send(
Base value,
ITransport transport,
Copy link
Contributor

Choose a reason for hiding this comment

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

The old send implementation had a way to disable sending to the SqlLite transport.

I know in our connectors we always want to default to that, but its not a good solution always.
In server side apps and automate functions, we specifically prefer not to use an sqllite cache. If it makes any sense to cache the objects, a memory transport is a much preferred way.

We should have a simple mechanism, like the useDefaultCache flag to have that flexibility.

Copy link
Member Author

Choose a reason for hiding this comment

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

Gergo and I had a quick discussion about this. There's a couple things we can do to make it clearer which overloads can be used.
I'm going to make some changes and we can discuss the improvement

Copy link
Member Author

Choose a reason for hiding this comment

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

@gjedlicska I've implemented the changes we discussed, + a couple of other minor tweaks following Alans suggestion.

The single transport overload now accepts a UseDefaultCache.
We've made it non-optional for a couple reasons.
1. We want caller to be explicit about the transports that are being used when sending.
2. It helps make the difference between the two overloads more explicit, and prevent misunderstandings
3. It also means our new overloads conflict less with existing ones, aiding backwards compat.

The overload that takes multiple transports has been renamed to Send to make the two overloads super clear.

CancellationToken cancellationToken = default
)
{
if (transport is null)
Copy link
Contributor

@BovineOx BovineOx Dec 5, 2023

Choose a reason for hiding this comment

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

Is this necessary anymore? transport isn't nullable, calling this and ignoring the contract would be a bit daft. We're throwing anyways, without only slightly more context, meaning an NRE would be pretty obvious...

Copy link
Member Author

Choose a reason for hiding this comment

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

I've changed this with my latest changes, we are no longer doing this check for transports.
However, I've still kept it in for value, since I'm not confident that it would throw lower down (we CAN serialize a null) but in the context of a send, we don't want users doing this.

If we were in .NET Standard2.1, we would want to mark the parameter as nullable, but use the [NotNull] to say that this function will always throw when a null is passed in. see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis
We can use Polysharp to bring this attribute back to us, but we haven't got that setup (tho, I believe we're no longer blocked on the CI side)

So for now, I think this is fine.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've changed it again.
The single transport version is truly nullable, with the useDefaultCache bool exposed. Now the null check is a feature, not a bug. And with it the DX should be improved.

@@ -47,7 +46,7 @@ public static partial class Operations
/// </summary>
/// <param name="objects"></param>
/// <returns></returns>
[Obsolete("Please use the Serialize(Base @object) function. This function will be removed in later versions.")]
[Obsolete("Please use the Serialize(Base @object) function. This function will be removed in later versions.", true)]
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this need to now be (Base value) ?

Copy link
Member Author

Choose a reason for hiding this comment

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

It should be, I'll fix in another PR

/// <exception cref="ArgumentException">The provided arguments are not valid</exception>
/// <exception cref="OperationCanceledException"></exception>
/// <exception cref="InvalidOperationException">The transport was in an invalid state</exception>
/// <exception cref="OperationCanceledException"><see cref="CancellationToken"/> requested cancel</exception>
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, beyond scope but the commented out GetBlock() call below? Worth binning it while we are here?

Copy link
Member Author

@JR-Morgan JR-Morgan Dec 5, 2023

Choose a reason for hiding this comment

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

Depends whether you consider this a comment to stop developers adding a GetBlob function back later down the road.
I'll leave this decision up to @gjedlicska

@JR-Morgan JR-Morgan marked this pull request as ready for review December 5, 2023 23:10
@JR-Morgan
Copy link
Member Author

I would have liked to make this change 100% non-breaking, allowing devs currently using Send to have their code still compile and work 100%.

This will be true for most cases, there are a couple permutation of positional and keyword args where devs will now see a compiler error saying "parameter mismatch" or "Could not find suitable method, candidates are...".

image

Unless we are prepared to change the name of our new Send function, this is unavoidable.

I would suggest that this shouldn't be a blocker. Any changes to overloads are technically breaking when you look at various positional keyword args. We have made far more breaking changes only last release with the inclusion of some extra functions in ISpeckleConverter,


To get a flavour for how likely this is to affect users. All existing uses of send within our codebase (with the exception of a single one in our integration tests) were no breaking.

@JR-Morgan JR-Morgan added this to the 2.18 milestone Dec 6, 2023
@JR-Morgan JR-Morgan added core issues related to the .net sdk. chore tech debt and removed chore labels Dec 6, 2023
@JR-Morgan JR-Morgan self-assigned this Dec 6, 2023
@AlanRynne AlanRynne changed the title Feat(Core)!: CNX 8352 operations.send feat(Core): CNX-8352 operations.send Dec 11, 2023
Copy link
Member

@AlanRynne AlanRynne left a comment

Choose a reason for hiding this comment

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

Reviewed this live with Jedd on Friday. Changes look good and I'd accept the slight breaking change due to parameter mismatch or ambiguous call

@JR-Morgan JR-Morgan merged commit d358727 into dev Dec 12, 2023
30 checks passed
@JR-Morgan JR-Morgan deleted the CNX-8352-Operations.Send branch December 12, 2023 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core issues related to the .net sdk. tech debt
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants