Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Conversation

@ericstj
Copy link
Member

@ericstj ericstj commented May 29, 2019

There were two resx scenarios that we weren't handling well.

  1. BinaryFormatted data that is missing the type information

BinaryFormatted data never takes the type into account, it's only used
to check the deserialized data after it's read. In the old resx reader
it would deserialize the data in the build task, only to reserialize it
back, recording the type information. Since we're eliminating build
time deserialziation we cannot do this, so just permit the payload to
flow through without recording the type information. This is
effectively what happened before since the user never recorded the
type information in the resx so it isn't introducing any new opportunity
for inconsistencies. To implement this I used the existing ResX format
with a sentinel type to indicate that the BinaryFormatter payload type
was unknown.

  1. Primitive types stored as string

ResX reader deserialized all types during the build, we're trying to
eliminate this as it results in build time / cross-framework type
loading. In doing so we lose the ability to handle primitive types
since the only way we currently write primitive types is when they
are passed in as live objects. To fix this, we'll make the string-based
type converter method aware of primitive types, and permit it to
deserialize those primitive types (IOW: parse the string via
typeconverter) so that we still write these as primitive resources.
We'll rename this method to AddResource to indicate it is more
generic than just handling pre-serialized data. To identify primitive types
we use a string comparer to match the type name written in the resx,
and map it to a known type (in the build framework).

There were two resx scenarios that we weren't handling well.

1. BinaryFormatted data that is missing the type information

BinaryFormatted data never takes the type into account, it's only used
to check the deserialized data after it's read.  In the old resx reader
it would deserialize the data in the build task, only to reserialize it
back, recording the type information.  Since we're eliminating build
time deserialziation we cannot do this, so just permit the payload to
flow through without recording the type information.  This is
effectively what happened before since the user never recorded the
type information in the resx so it isn't introducing any new opportunity
for inconsistencies.  To implement this I used the existing ResX format
with a sentinel type to indicate that the BinaryFormatter payload type
was unknown.

2. Primitive types stored as string

ResX reader deserialized all types during the build, we're trying to
eliminate this as it results in build time / cross-framework type
loading.  In doing so we lose the ability to handle primitive types
since the only way we currently write primitive types is when they
are passed in as live objects.  To fix this, we'll make the string-based
type converter method aware of primitive types, and permit it to
deserialize those primitive types (IOW: parse the string via
typeconverter) so that we still write these as primitive resources.
We'll rename this method to AddResource to indicate it is more
generic than just handling pre-serialized data.  To identify primitive types
we use a string comparer to match the type name written in the resx,
and map it to a known type (in the build framework).
@ericstj ericstj requested review from rainersigwald and tarekgh May 29, 2019 07:41
@ericstj
Copy link
Member Author

ericstj commented May 29, 2019

@ViktorHofer have a look at this: https://mc.dot.net/#/user/dotnet-bot/pr~2Fdotnet~2Fcorefx~2Frefs~2Fpull~2F38012~2Fmerge/test~2Ffunctional~2Fcli~2Finnerloop~2F/20190529.1/workItem/System.Runtime.WindowsRuntime.Tests/wilogs. Tests passed but the job was fire-balled because some script activity after the test timed out. What is it doing?

@ericstj
Copy link
Member Author

ericstj commented May 29, 2019

Linux musl failures all appear to be https://github.com/dotnet/core-eng/issues/6327. Which @MattGal is working on.

@ViktorHofer
Copy link
Member

@ViktorHofer have a look at this: https://mc.dot.net/#/user/dotnet-bot/pr~2Fdotnet~2Fcorefx~2Frefs~2Fpull~2F38012~2Fmerge/test~2Ffunctional~2Fcli~2Finnerloop~2F/20190529.1/workItem/System.Runtime.WindowsRuntime.Tests/wilogs. Tests passed but the job was fire-balled because some script activity after the test timed out. What is it doing?

@MattGal it seems you are doing additional logic after the test invocation which modifies the ExitCode. I thought you were capturing the ExitCode and set it at the end of the script but apparently that's not the case.

@MattGal
Copy link
Member

MattGal commented May 29, 2019

@ViktorHofer yes, this is what is called a "timeout". That means the work item ran longer than it was expected to, and was killed. As a timed-out work item has no exit code, I had to pick one, which years ago I arbitrarily picked -3 for (as it doesn't match common Windows/Linux exit codes). We also send events to make it disambiguate-able from a real exit -3, though either is a failure.

You can tell this from the logs:

2019-05-29 08:45:22,436: ERROR: job(46): kill: Job running for too long. Killing...
2019-05-29 08:45:22,436: ERROR: executor(561): _execute_command: Executor timed out after 900 seconds and was killed.
2019-05-29 08:45:22,436: INFO: event(44): send: Sending event type WorkItemTimeout
2019-05-29 08:45:22,577: INFO: saferequests(87): request_with_retry: Response complete with status code '201'
2019-05-29 08:45:22,577: INFO: executor(581): _execute_command: Finished _execute_command, exit code: -3

Common causes for this include variable-length work item timing, too-short of a timeout being set for a given work item, extreme network slowness, or issues with a service the work item is talking to. Guessing from the logs here something took a long time in test-reporter.py but it didn't keep logging.

@ViktorHofer
Copy link
Member

OK I didn't look into the py script. Thanks!

@ericstj
Copy link
Member Author

ericstj commented May 29, 2019

I recognized this is a timeout, however the test itself finished with plenty of time left. The thing that timed out was a bunch of shady post-test activity involving installing python which I don't think is any of ours...

Test log:

----- start  8:30:25.47
...
=== TEST EXECUTION SUMMARY ===
   System.Runtime.WindowsRuntime.Tests  Total: 292, Errors: 0, Failed: 0, Skipped: 0, Time: 2.440s
...
----- end  8:34:28.75 ----- exit code 0 ----------------------------------------------------------
 Wed 05/29/2019- 8:34:28.92
Using base prefix 'C:\\python3.7.0'
...

Then in the run_client.py log:

2019-05-29 08:45:22,436: ERROR: job(46): kill: Job running for too long. Killing...
2019-05-29 08:45:22,436: ERROR: executor(561): _execute_command: Executor timed out after 900 seconds and was killed.

So whatever started after the test completed ran for another 10 minutes and eventually caused the test to be killed.

@MattGal
Copy link
Member

MattGal commented May 29, 2019

@ericstj That's a good question for @alexperovich when he gets in, he wrote the test-reporter python script which comes from dotnet/arcade. Usually that script logs more to the console, but my most likely guess as to what could have gone wrong would be network slowness in the VSTS API, which is what this reporter script spends most of its time doing. From a Helix client's perspective it's currently a black box. You told it to do something and kill it if it ran > 15 minutes, it took > 15 minutes.

I know there's an effort to make the VSTS API reporting occur outside your timeout, but I wouldn't expect this for about a month or so (as it will require a fair bit of plumbing and teaching the Helix client about VSTS)

@ericstj
Copy link
Member Author

ericstj commented May 29, 2019

Looked to me like it was just spending 10 minutes installing python, but it could be that he just forgot to log anything from that script.

@alexperovich
Copy link
Member

That test reporter script needs to use pip to install the vsts package so it can talk to azure devops to report test results. If the network is having problems on that machine I can see that install taking 10 minutes. It is only done once per machine though so it won't happen again on the same machine.
The first line of the python script is a print() so it never actually got to running the reporter. It did some pip installing and then hit a timeout.

We could probably add some machine setup stuff to do this install when we setup the machines.

@ViktorHofer
Copy link
Member

We could probably add some machine setup stuff to do this install when we setup the machines.

That would be a good idea.

Copy link
Member

@tarekgh tarekgh left a comment

Choose a reason for hiding this comment

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

Other than my questions/Comments, LGTM

@ericstj ericstj closed this May 31, 2019
@ericstj ericstj reopened this May 31, 2019
@ericstj
Copy link
Member Author

ericstj commented May 31, 2019

// directly add strings
if (primitiveType == typeof(string))
{
AddResource(name, value);
Copy link
Member

Choose a reason for hiding this comment

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

This is interesting, since I have similar code in the resgen task. But that also has to handle the ResXFileRef->text file with specified encoding case, so I don't think I can just rely on this. I don't see a reason to not have it, though.

Copy link
Member Author

Choose a reason for hiding this comment

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

My thought was that you can pretty much plumb the no-mime-type/non-ResXFileRef case straight through to this API. For mime-types and ResXFileRef you'll need to do some work in translating to different calls. Hopefully those can largely just pass the string value of the type through. Let me know if you have cases where those methods require "primitive type" knowledge.

// Compare two type names ignoring version
// If a type name is missing assembly, we assume it came from mscorlib
// since this is what Type.GetType will do.
public bool Equals(string assemblyQualifiedTypeName1, string assemblyQualifiedTypeName2)
Copy link
Member

Choose a reason for hiding this comment

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

@benvillalobos, just making you aware of this. I suspect we're going to want to have a very similar spanified implementation in RAR at some point.

Copy link
Member Author

Choose a reason for hiding this comment

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

Be careful about the mscorlib-isms and the missing name cases here. Those aren't so general purpose. Also note that I didn't bother improving the comparison of culture/key that could be done in a non-allocating way if you care about perf. Also this ignores version which RAR very much cares about. This is more of a reference and not a reusable bit of code.

public void AddResource(string name, System.IO.Stream value, bool closeAfterWrite = false) { }
public void AddResource(string name, object value) { }
public void AddResource(string name, string value) { }
public void AddResource(string name, string typeName, string value) { }
Copy link
Member

Choose a reason for hiding this comment

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

I don't feel strongly about AddResource(string, string, string) versus AddTypeConverterResource(string, string, string) writing different things to the .resources file depending on the types involved. From my perspective, that's an implementation detail I don't deeply care about, but I don't mind the rename either.

Co-Authored-By: Rainer Sigwald <raines@microsoft.com>
@ericstj ericstj closed this May 31, 2019
@ericstj ericstj reopened this May 31, 2019
@ericstj ericstj closed this May 31, 2019
@ericstj ericstj reopened this May 31, 2019
@ericstj ericstj closed this Jun 1, 2019
@ericstj ericstj reopened this Jun 1, 2019
@ericstj ericstj closed this Jun 3, 2019
@ericstj ericstj reopened this Jun 3, 2019
@ericstj
Copy link
Member Author

ericstj commented Jun 4, 2019

Merging. If we get feedback on API we can address in mop up PR.

@ericstj ericstj merged commit 00c7405 into dotnet:master Jun 4, 2019
rainersigwald added a commit to rainersigwald/msbuild that referenced this pull request Jun 6, 2019
Includes a darc subscription for System.Resources.Extensions and
reaction to dotnet/corefx#38012:

* AddResource(string,string,string) instead of removed
   AddTypeConverterResource
* Stop specifying type for BinaryFormattedResource.
@karelz karelz added this to the 3.0 milestone Jul 16, 2019
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
* Better handle resx scenarios

There were two resx scenarios that we weren't handling well.

1. BinaryFormatted data that is missing the type information

BinaryFormatted data never takes the type into account, it's only used
to check the deserialized data after it's read.  In the old resx reader
it would deserialize the data in the build task, only to reserialize it
back, recording the type information.  Since we're eliminating build
time deserialziation we cannot do this, so just permit the payload to
flow through without recording the type information.  This is
effectively what happened before since the user never recorded the
type information in the resx so it isn't introducing any new opportunity
for inconsistencies.  To implement this I used the existing ResX format
with a sentinel type to indicate that the BinaryFormatter payload type
was unknown.

2. Primitive types stored as string

ResX reader deserialized all types during the build, we're trying to
eliminate this as it results in build time / cross-framework type
loading.  In doing so we lose the ability to handle primitive types
since the only way we currently write primitive types is when they
are passed in as live objects.  To fix this, we'll make the string-based
type converter method aware of primitive types, and permit it to
deserialize those primitive types (IOW: parse the string via
typeconverter) so that we still write these as primitive resources.
We'll rename this method to AddResource to indicate it is more
generic than just handling pre-serialized data.  To identify primitive types
we use a string comparer to match the type name written in the resx,
and map it to a known type (in the build framework).

* Respond to feedback

* Apply suggestions from code review

Co-Authored-By: Rainer Sigwald <raines@microsoft.com>


Commit migrated from dotnet/corefx@00c7405
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants