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

WebServiceTarget - FlushAsync - Avoid premature flush #1868

Merged
merged 4 commits into from
Jan 11, 2017

Conversation

snakefoot
Copy link
Contributor

@snakefoot snakefoot commented Dec 19, 2016

Keeps track of pendingRequests. Tries to fix #259. Instead of expecting async-target to almost handle it #1853

First idea was to keep track of each individual LogEvent (in a dictionary), but the logic (and the allocations) became a little heavy. Now it just keeps track of a pending request count, so it is not completely correct when races occurs, but I think it is good enough.


This change is Reviewable

@codecov-io
Copy link

codecov-io commented Dec 19, 2016

Current coverage is 81% (diff: 92%)

Merging #1868 into master will increase coverage by <1%

@@             master      #1868   diff @@
==========================================
  Files           276        277     +1   
  Lines         18634      18748   +114   
  Methods        2861       2873    +12   
  Messages          0          0          
  Branches       2139       2148     +9   
==========================================
+ Hits          15138      15260   +122   
- Misses         2977       2984     +7   
+ Partials        519        504    -15   

Sunburst

Powered by Codecov. Last update 2216fff...89a8519

foreach (var key in new List<HttpWebRequest>(_pendingRequests.Keys))
{
KeyValuePair<DateTime, AsyncContinuation> flushCallback;
if (_pendingRequests.TryGetValue(key, out flushCallback))
Copy link
Member

Choose a reason for hiding this comment

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

don't we need a lock here?

Copy link
Contributor Author

@snakefoot snakefoot Dec 19, 2016

Choose a reason for hiding this comment

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

FlushAsync is already protected by this.SyncRoot. Same lock-object is used for the other manipulations. But I can add an explicit lock, so it will not confuse.

Copy link
Member

Choose a reason for hiding this comment

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

Missed that, thx! No need to add it IMO then

Copy link
Member

@304NotModified 304NotModified left a comment

Choose a reason for hiding this comment

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

great that we could close that old issue :)

Some questions, see code notes

catch (NLog.NLogRuntimeException)
{ }
LogManager.Flush(); // Waits for flush (Scheduled on top of the previous flush)
LogManager.Flush(); // Nothing to flush
Copy link
Member

Choose a reason for hiding this comment

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

should users also do a triple-flush?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No triple flush is only for code-coverage :)

Copy link
Member

Choose a reason for hiding this comment

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

sounds we should have split those tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -180,6 +180,7 @@ public WebServiceTarget(string name) : this()
/// <docgen category='Web Service Options' order='10' />
public string XmlRootNamespace { get; set; }

private readonly Dictionary<HttpWebRequest, KeyValuePair<DateTime,AsyncContinuation>> _pendingRequests = new Dictionary<HttpWebRequest, KeyValuePair<DateTime,AsyncContinuation>>();
Copy link
Member

Choose a reason for hiding this comment

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

isn't HttpWebRequest an expensive key value?

Copy link
Member

Choose a reason for hiding this comment

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

Another way would be using a linkedlist and send the info with the AsyncContinuation (if possible)?

Copy link
Contributor Author

@snakefoot snakefoot Dec 19, 2016

Choose a reason for hiding this comment

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

isn't HttpWebRequest an expensive key value?

I was hoping it was acting like a normal class, and just used default class-reference-hashcode.

Another way would be using a linkedlist

Yet another option is just to monitor the last written LogEvent.

And yet yet another option is to have a single counter of outstanding requests, and then keep a queue of flush-callbacks. When a flush is requested one caches the pending request count, and when it reaches zero, then it fires the flush-callback. Then it would only be a list of pending flush-callbacks and a pending-counter.

Copy link
Member

Choose a reason for hiding this comment

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

I was hoping it was acting like a normal class, and just used default class-reference-hashcode.

yes 're right!

// The default implementation returns the sync block index for this instance.
// Calling it on the same object multiple times will return the same value, so
// it will technically meet the needs of a hash function, but it's less than ideal.
// Objects (& especially value classes) should override this method.

https://referencesource.microsoft.com/#mscorlib/system/object.cs,4de9cf234d0d8b16

@snakefoot
Copy link
Contributor Author

snakefoot commented Dec 19, 2016

Have now also added AutoFlushTargetWrapper into the mix, since #259 also complains that using the AutoFlushTargetWrapper didn't solve their problem.

Now I also have the crutch (AutoFlushTargetWrapper) that people can use when having a target without a proper flush-method.

Have decided not to keep track of the individual logevents, but just have a pending-counter, and then just keep track of the pending flush-requests instead.

@snakefoot snakefoot force-pushed the WebServiceTargetFlush branch 2 times, most recently from 437d10d to eb51d53 Compare January 2, 2017 22:25
@304NotModified
Copy link
Member

Reviewed 15 of 17 files at r2, 3 of 3 files at r3.
Review status: all files reviewed at latest revision, 1 unresolved discussion.


tests/NLog.UnitTests/Targets/WebServiceTargetTests.cs, line 626 at r3 (raw file):

                    CountdownEvent = new CountdownEvent(expectedMessages);
                else
                    CountdownEvent = null;

nice one :)


Comments from Reviewable

@snakefoot
Copy link
Contributor Author

snakefoot commented Jan 13, 2017

@304NotModified Think I have broken something, as the test-builds are now failing quite frequently, after the merge.

Have found the problem. I had broken broken the wait-counter for the two tests. See #1903

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bug report / Bug fix webservice-target
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants