-
Notifications
You must be signed in to change notification settings - Fork 199
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
Implementing Retry logic [Reliable Channel] #556
Conversation
…ity. Added extension to return the timeout values as expected before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One general change that is required is Java doc comments are missing all over. We need that especially for new public methods and also some private methods which have important logic.
Try to reduce the scope of public methods exposed if possible. I think some can be done.
I did an initial glance over on this, and we would do a functional review soon.
@@ -65,6 +66,7 @@ shadowJar { | |||
relocate 'org.apache.commons', 'com.microsoft.applicationinsights.core.dependencies.apachecommons' | |||
relocate 'com.google.common', 'com.microsoft.applicationinsights.core.dependencies.googlecommon' | |||
relocate 'javax.annotation', 'com.microsoft.applicationinsights.core.dependencies.javaxannotation' | |||
relocate 'com.google.gson', 'com.microsoft.applicationinsights.core.dependencies.gson' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you use gson for actual code? Or this is only for test? If it is only test I would say do not relocate. Relocation usually should be done when it is absolutely necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added Gson to take care of the parsing of the BackendResponse object that is returned from a partial success. There were no JSON deserializers already included in the solution (at least none that were obvious).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@debugthings makes sense. Gson was used but only for test cases. Since this is now used for production code we do need to shade it. May be we might not need to shade it still. Gradle will pull this as transitive dependency when building. Shading (i.e repacking) to microsoft domain is only needed when it interferes our agent (one example is apache http client). We shade it to avoid instrumenting the calls sdk makes using it. Gson is a widely used library across java and I would rather avoid shading to prevent us from falling into the traps of class path hells.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, I also thought that we include it to avoid having to distribute gson with it for instances where this is a drop in addition like a 3rd party.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that was one reason but, this creates problems of dependency hells if we miss proper shading, and more over if the user uses dependency management, which most do then transient dependencies get pulled down. Further as the SDK grows and we start using more libraries, it would make sense to just shade the one which interfer the operation and leave the rest
|
||
public class BackendResponse { | ||
|
||
public int itemsReceived; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adjust the additional space
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
validateTransmissionAndSend(args); | ||
} | ||
|
||
public boolean validateTransmissionAndSend(TransmissionHandlerArgs args) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this method need to be public? If it is not accessed from outside, reduce the scope to private or default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The answer is no, I did this to get my tests working in. I attempted to use Mockito for this, but in version 1.10 they do not support private methods or final classes. This makes it hard to mock a number of items.
Since we have the need to document all public methods I can modify the tests to use Reflection to grab the private member.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah so mockito version 1.10 does not allow mocking private methods. Is this method a part of interface? That's why I was suggesting since this is used widely we can plug it into the interface and then mock it. If that route is not valid for some reason then we might better use reflection. Reducing the publicly exposed methods will improve our abilities to modify it without affecting anyone. Users can take dependency on public methods and modification of signature can thus be very cumbersome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed this by using the package scope. Only classes defined in the packages can see the method.
Gson gson = gsonBuilder.create(); | ||
backend = gson.fromJson(response, BackendResponse.class); | ||
} catch (Throwable t) { | ||
InternalLogger.INSTANCE.trace("Error deserializing backend response with Gson, message: %s", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please print the stack trace also. ExceptionUtils can be used for this.
|
||
// In case the 206 was false we can break here | ||
if(beR != null && (beR.itemsAccepted == beR.itemsReceived)) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there should be a log message here, with lowest severity.
case HttpStatus.SC_REQUEST_TIMEOUT: | ||
case HttpStatus.SC_INTERNAL_SERVER_ERROR: | ||
case HttpStatus.SC_SERVICE_UNAVAILABLE: | ||
case 429: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we don't handle 429 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh? In the partial success handler any an all error messages are treated the same. In this instance the partial success will try to resend any of these items in the next transmission.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah got it. So this means if partial message was accepted, then we would retry the whole packet correct?
} | ||
} catch (IOException e1) { | ||
// TODO Auto-generated catch block | ||
e1.printStackTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't print stack trace. Instead dump it using Internal Logger
|
||
} | ||
|
||
private static Date convertToDateToGmt(Date date) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need java docs for all the methods and their description. It is crucial for all public methods and private methodsl like this where there is core logic.
validateTransmissionAndSend(args); | ||
} | ||
|
||
public boolean validateTransmissionAndSend(TransmissionHandlerArgs args) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to previous does this method need to be public. More-ever can we create an abstraction for this too, like an interface because it seems like this is being used in different handler classes you created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed this by using the package scope. Only classes defined in the packages can see the method.
return true; | ||
|
||
} catch (ConnectionPoolTimeoutException e) { | ||
ex = e; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All this places we need to dump the stack trace. Please use ExceptionUtils to do so and pass it in logger.
public void setResponseCode(int code) { this.responseCode = code;} | ||
public int getResponseCode() { return this.responseCode;} | ||
|
||
private Throwable exception; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@debugthings do we ever get a Throwable here? I think most of the time it would get an instance of Exception class. If you know any place where this could be Throwable please let me know
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the original implementation they catch Throwable for logging. I also consume it here incase there is an Error and want to retry the transmission.
Which is then added here
https://github.com/Microsoft/ApplicationInsights-Java/blob/1e5d72cadd24cb75b46d577ef0f8c3828fc87e19/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionNetworkOutput.java#L209
And then null checked here
https://github.com/Microsoft/ApplicationInsights-Java/blob/1e5d72cadd24cb75b46d577ef0f8c3828fc87e19/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/ErrorHandler.java#L56
@@ -46,8 +50,16 @@ | |||
* | |||
* Created by gupele on 6/29/2015. | |||
*/ | |||
public final class TransmissionPolicyManager implements Stoppable { | |||
|
|||
public final class TransmissionPolicyManager implements Stoppable, TransmissionHandlerObserver { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we had to change the public class also, I think which is fine. However, if some of our users if they had taken dependency on this. we would break them by this change. I am not sure we might need to consider a separate release for this, mentioning that there can be some breaking changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe. We added four public methods to this but did not remove any; and didn't change the implementation of existing methods. That shouldn't break the contract and the code should execute as expected. Might well warrant a deeper discussion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm
* @return A List<> of each sent item | ||
*/ | ||
List<String> generateOriginalItems(TransmissionHandlerArgs args) { | ||
List<String> originalItems = new ArrayList<String>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Types in <> in Java 7 and onwards can be auto-inferred and is more efficient. This can be replaced with
List originalItems = new ArrayList<>();
List<String> originalItems = generateOriginalItems(args); | ||
|
||
// Somehow the amount of items received and the items sent do not match | ||
if (beR != null && (originalItems.size() != beR.itemsReceived)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest to make this condition more robust. This could be more apt
if (beR != null && (originalItems.size() < beR.itemsReceived))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I agree, if these numbers don't match then there was a problem with the transmission and we're in an invalid state I would think. Either the original content was broken or the response is broken
return false; | ||
} | ||
|
||
if (beR != null && (beR.itemsAccepted != beR.itemsReceived)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly for this the condition can be changed to
if (beR != null && (beR.itemsAccepted < beR.itemsReceived)
This makes it logically more clear and better readable code. IMO the condition in itself is also more robust.
if (beR != null && (beR.itemsAccepted != beR.itemsReceived)) { | ||
|
||
List<String> newTransmission = new ArrayList<String>(); | ||
for (BackendResponse.Error e : beR.errors) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we replace this for-each loop with a for loop like this :
for (int i = 0; i < ber.errors.length; ++i). This would help simplify the index operation being used mutiple times. We can the just do
if (i < originalItems.size()) {
newTransmission.add(originalItems.get(i));
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The index of the items in the errors array is not guaranteed to be the index of the original item sent.
errors[0] = Error() { index = 2, responseCode = 500, message = "Internal Error" }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah this is a catch. Got it
boolean validateTransmissionAndSend(TransmissionHandlerArgs args) { | ||
if (args.getRetryHeader() != null && args.getTransmission() != null | ||
&& args.getTransmissionDispatcher() != null) { | ||
args.getTransmission().incrementNumberOfSends(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that PartialResponseHandler class doesn't increment the number of sends like this. Is there a reason why it is omitted there? Because eventually we are retrying correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this instance we're creating a brand new transmission to send based on the result of the old one. We are not going to dispatch the entire transmission so no need to increment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
Date date = formatter.parse(retryAfterAsString); | ||
|
||
Date now = Calendar.getInstance().getTime(); | ||
long retryAfterAsSeconds = (date.getTime() - convertToDateToGmt(now).getTime()) / 1000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this calculation is always fixed. I might have missed something , please point out to where we are doing exponential backoff in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Throttling requests the server provides the backoff time in the form of the Retry-After header. If that header is missing or invalid (will throw) I call backoff in the catch block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. I would say to mention a comment!
@@ -68,6 +68,15 @@ public SenderThreadLocalBackOffData(long[] backOffTimeoutsInMillis, long addMill | |||
public boolean isTryingToSend() { | |||
return currentBackOffIndex != -1; | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing Java docs for getCurrentBackOffMillis()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed, removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay
} | ||
} | ||
|
||
public long backOffTimerValue() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Java docs missing for this method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
@@ -75,6 +80,11 @@ public synchronized void stopAllSendersBackOffActivities() { | |||
} | |||
stopped = true; | |||
} | |||
|
|||
public long getCurrentBackoffMillis() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
@@ -24,8 +24,9 @@ | |||
/** | |||
* Created by gupele on 6/29/2015. | |||
*/ | |||
enum TransmissionPolicy { | |||
public enum TransmissionPolicy { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update java docs for this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed public.
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* The class is responsible for the actual sending of {@link com.microsoft.applicationinsights.internal.channel.common.Transmission} | ||
* The class is responsible for the actual sending of | ||
* {@link com.microsoft.applicationinsights.internal.channel.common.Transmission} | ||
* | ||
* The class uses Apache's HttpClient framework for that. | ||
* | ||
* Created by gupele on 12/18/2014. | ||
*/ | ||
public final class TransmissionNetworkOutput implements TransmissionOutput { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are bunch of methods in this class which do not have java docs. It would be good if we can update those places as we are changing this part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added docs for public and private methods.
|
||
public final class TransmissionPolicyManager implements Stoppable, TransmissionHandlerObserver { | ||
|
||
private final int DEFAULT_MAX_SECONDS_TO_PAUSE_AFTER_MAX_BACKOFF = 600; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did we came up with this number ? 600 Seconds seems to be too long. In a situation where the network is very restricted this would accumulate bulk of telemetry. Also is this configurable by channel in xml? If not it should be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, 10 minutes is a long time and it should be configurable. In the .NET implementation it will max out at 30 minutes in the backoff algorithm. Let's talk about this a bit more to see what we really want to do. By the time we reach this point we would have executed the backoff 15 times and probably have been throttled well over 15 minutes. It's possible this is just redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@debugthings Yes, ideally I would want that to be configurable too. So instead of keeping that 15 constants for back of we have some sort of iterator pattern implemented which keeps on providing new backoff numbers until user specified limit. Internally iterator could well be implemented as Geometric Progression with ratio of 2. If we want to interleave with a constant time that could also be done.
if (args.getTransmission() != null && args.getTransmissionDispatcher() != null) { | ||
switch (args.getResponseCode()) { | ||
case HttpStatus.SC_PARTIAL_CONTENT: | ||
BackendResponse beR = getBackendResponse(args.getResponseBody()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit picking: Please use a more descriptive name instead of beR. "backendResponse" would be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, fixed.
|
||
|
||
List<String> newTransmission = new ArrayList<String>(); | ||
for (BackendResponse.Error e : beR.errors) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null check missing for beR. I'd suggest checking for null right after line 39.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed with logic update
@@ -24,7 +24,7 @@ | |||
/** | |||
* Created by gupele on 2/10/2015. | |||
*/ | |||
enum TransmissionSendResult { | |||
public enum TransmissionSendResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to make this enum public? Is it required for test cases? If yes please follow the Java Doc requirements and update the comment to be java doc comment with description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah, must have been done via some Intellisense suggestion. Removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, got it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have done second round of review and left my comments. I would like to have those changes. Further, I am mandating the need of java docs and being a little bit stricter on this because we are following this requirement for all new check-ins and is also mandatory for quality API
Moved the Handlers out of the concrete package to the common package to keep the same consistency. Removed a couple of unessecary methods. Added docs.
} catch (ConnectionPoolTimeoutException e) { | ||
ex = e; | ||
InternalLogger.INSTANCE.error( | ||
"Failed to send, connection pool timeout exception\r\n" + "Stack Trace:\r\n" + "%s", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use %n
and the format string chooses the correct EOL characters. Same with the rest of the log messages.
Also, let's remove the unnecessary concatenations; I don't know if JIT is smart enough to optimize this into one string literal. Let's assume it's not and merge these into one string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, eclipse auto format causes this most likely because I'm not using the %n string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked it up and JIT is smart enough to turn those into one literal, so I'm less concerned with the concatenation. :)
@@ -135,11 +135,13 @@ public TransmissionFileSystemOutput(String folderPath) { | |||
@Override | |||
public boolean send(Transmission transmission) { | |||
if (size.get() >= capacityInKB) { | |||
InternalLogger.INSTANCE.logAlways(InternalLogger.LoggingLevel.TRACE, "Persistent storage max capcity has been reached; currently at %s KB. Telemetry will be lost, please set the MaxTransmissionStorageFilesCapacityInMB property in the configuration file.", size.get()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a WARN
level log. It's an exceptional case, but everything is still operational.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think things are operational, however when this would happen it would indicate loss of telemetry. Imagine a banking application where this occurs and they loss transactional logs which were eventually needed for fraud analysis then this could be critical information. I would keep it as logalways and since this is rare I don't think it would any how effect production loads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm suggesting changing it to InternalLogger.INSTANCE.logAlways(InternalLogger.LoggingLevel.WARN, ...
I also think it should be logAlways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, WARN makes more sense as it's something that is actionable but not ex
return false; | ||
} | ||
|
||
Optional<File> tempTransmissionFile = createTemporaryFile(); | ||
if (!tempTransmissionFile.isPresent()) { | ||
InternalLogger.INSTANCE.logAlways(InternalLogger.LoggingLevel.TRACE, "Persistent storage unable to create temporary file."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is an ERROR
level log. We can still run (i.e. it's not FATAL), but this component cannot do what it's designed to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am removing this as it's redundant. There is a logger call in createTemporaryFile()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
case HttpStatus.SC_REQUEST_TIMEOUT: | ||
case HttpStatus.SC_INTERNAL_SERVER_ERROR: | ||
case HttpStatus.SC_SERVICE_UNAVAILABLE: | ||
case 429: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the 429 and 439 case, can you append those lines with comments with a "friendly name" (similar to the constants in the previous cases)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed with constants mentioned in other change.
case HttpStatus.SC_REQUEST_TIMEOUT: | ||
case HttpStatus.SC_INTERNAL_SERVER_ERROR: | ||
case HttpStatus.SC_SERVICE_UNAVAILABLE: | ||
case 429: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we create constants for 429 and 439?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think probably we should. It would allow when we extend the support later to support this codes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HttpStatus
is part of the Apache HttpClient. Will a comment be sufficient?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes more sense to have this as a constant. I modified TransmissionSendResult
as it wasn't used anywhere else and was internal to the com.microsoft.applicationinsights.internal.channel.common
package
return instanceIsActive; | ||
} catch (InterruptedException e) { | ||
return false; | ||
if (!instanceIsActive) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@debugthings is it true that thread will never starve in the same state (i.e blocked state). If not we might always hit this condition for certain thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this is an artifact of the blocking backoff implementation (which I left intact). The only way for this to get set is if someone calls stop(). It's highly unlikely that it will be called since it's not referenced anywhere in the code.
It's in place to make sure if someone wants to disable the backoff they can do so with stop. Not surprisingly there is no start method so once the manager is stopped that's it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there is a feature like this to disable the backoff it should be documented. And if there is no way to start if back then stop also doesn't make sense to me. Either case I think if we want to keep it just comment on it , regarding it is not advised to use this at any point or just remove the method if we do not plan to have this functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am all for deleting code that is not used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left this code intact as there are some old tests that are dependent on it and that is too much to tackle in this PR. Created task #559 to follow up
private TransmissionNetworkOutput(String serverUri, TransmissionPolicyManager transmissionPolicyManager) { | ||
Preconditions.checkNotNull(serverUri, "serverUri should be a valid non-null value"); | ||
Preconditions.checkArgument(!Strings.isNullOrEmpty(serverUri), "serverUri should be a valid non-null value"); | ||
Preconditions.checkNotNull(transmissionPolicyManager, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are scenarios where this could be null. How does code flow happen in case of this event?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Preconditions statements are for us. Callers of this method should make sure serverUri
is not null before calling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two minor comments
InternalLogger.INSTANCE.logAlways(InternalLogger.LoggingLevel.TRACE, "App is throttled, telemetry will be blocked for %s seconds.", backOffSeconds); | ||
this.suspendInSeconds(TransmissionPolicy.BACKOFF, backOffSeconds); | ||
} else { | ||
// TODO Remove Static Time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this TODO still needed?
|
||
public void clearBackoff() { | ||
policyState.setCurrentState(TransmissionPolicy.UNBLOCKED); | ||
backoffManager.onDoneSending(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: extra spaces.
Replaced by #561 |
Added retry logic that is similar to the .NET framework.
https://github.com/Microsoft/ApplicationInsights-Java/blob/7a5e572b2ffd3256898c6bd05dc3bec6754e3629/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionNetworkOutput.java#L172
All exceptions are now handled by
ErrorHandler
in this line.https://github.com/Microsoft/ApplicationInsights-Java/blob/094383a25b0f98fe6aa2dd6dd58bae10259492e6/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/ErrorHandler.java#L39-L42
For significant contributions please make sure you have completed the following items: