Re: [go-nuts] net/http: question about RoundTripper

2020-05-15 Thread Anuj Agrawal
Thanks Kevin for these insights. It does seem like the documentation
notes were meant for Go core devs. It would have helped, if the
authors threw in more insight.

I have also been using RoundTripper as client middleware, but so far
largely for authentication. I wanted to expand the scope of the client
middleware in my implementations to do more but looking at the
RoundTripper documentation, I wanted to have views on its use and see
if I can find anti-patterns that I should be aware of.

In fact, since I could not find a lot of useful information around it,
I even felt like writing a blog post highlighting good and bad
patterns using RoundTripper based on the notes I collect.


On Tue, May 12, 2020 at 7:38 AM Kevin Conway  wrote:
>
> I'll make an attempt to answer this question but I could be wrong given some 
> deeper historical context between the early Go developers.
>
> There are two chunks of the http.RoundTripper comments that folks typically 
> ask about: "should not attempt to handle higher-level protocol details" and 
> "should not modify the request". Unfortunately, the rationale for why these 
> statements are made is neither presented in the comments nor in the patches 
> that introduced them.
>
> It appears "should not modify the request" most likely refers to a 
> concurrency issue that must be mitigated by copying the request before 
> mutating it in the RoundTripper. Here's the change that claims to have 
> resolved an issue surrounding this: https://codereview.appspot.com/5284041. 
> The original comments explicitly allowed for mutating the request but this 
> was changed to "should not" after this patch due to the bug that it resolved.
>
> It's a little harder to find direct evident of the author's intent for 
> "should not attempt to handle higher-level protocol details". This part of 
> the comment has been in the code for nearly a decade and it becomes fairly 
> difficult to track the origin past a set of major renames and large movements 
> of files from place to place within the early Go source code. Reading 
> https://github.com/golang/go/commit/e0a2c5d4b540934e06867710fe7137661a2a39ec 
> makes it seem like these notes were meant for the author or for other Go core 
> devs who were building the original HTTP stack rather than those of us who 
> would use it later. For example, it appears to signal that standard library 
> developers should isolate higher level features within the Client type rather 
> than in the ClientTransport (now RoundTripper) type. I haven't found 
> anything, yet, that suggests the comments are meant for anyone other than 
> developers of the http package in the Go standard library.
>
> From a more practical perspective, you don't really have another choice when 
> it comes to HTTP client middleware that are generally useful in Go 
> applications than the http.RoundTripper interface. If everyone applied the 
> "accept interfaces, return structs" guidelines then you would have more 
> options. For example, if everything that needed an HTTP client accepted a 
> "type Doer { Do(r *http.Request) (*http.Response, Error) }" style interface 
> then you could target your middleware as wrappers for the http.Client. 
> Unfortunately, most projects that allow for injection of a custom HTTP client 
> do so by accepting an instance of *http.Client. Accepting that specific, 
> concrete type makes wrapping anything other than the http.RoundTripper a 
> practical impossibility.
>
> Personally, I've been using http.RoundTripper middleware for several years 
> without issue. It's a solid pattern that can provide an enormous amount of 
> value by allowing re-usable layers of behavior that can be injected into 
> virtually any library or framework that uses an HTTP client. I don't worry 
> about the comments in the standard library for the reasons I listed.
>
> On Mon, May 11, 2020 at 2:01 PM Anuj Agrawal  wrote:
>>
>> I am trying to understand in what cases would it make sense to
>> implement my own RoundTripper.
>>
>> If I search about it, I come across examples of RoundTripper that try
>> to do things like caching, retries, authentication, etc. I also read
>> somewhere that there are many RoundTripper implementations that just
>> set the User-Agent header on a request.
>>
>> I know that the documentation says "RoundTrip should not attempt to
>> handle higher-level protocol details such as redirects,
>> authentication, or cookies." And, I also understand that RoundTripper
>> would be a bad place for things like caching.
>>
>> However, I am not able to figure out why is it such a bad idea to use
>> RoundTripper as a middleware that allows me to do so

[go-nuts] net/http: question about RoundTripper

2020-05-11 Thread Anuj Agrawal
I am trying to understand in what cases would it make sense to
implement my own RoundTripper.

If I search about it, I come across examples of RoundTripper that try
to do things like caching, retries, authentication, etc. I also read
somewhere that there are many RoundTripper implementations that just
set the User-Agent header on a request.

I know that the documentation says "RoundTrip should not attempt to
handle higher-level protocol details such as redirects,
authentication, or cookies." And, I also understand that RoundTripper
would be a bad place for things like caching.

However, I am not able to figure out why is it such a bad idea to use
RoundTripper as a middleware that allows me to do some of the higher
level things like authentication. After all, authentication is just
about interpreting and/or manipulating some headers. In some cases, it
could be just as good as setting the User-Agent where all that happens
is setting the Authorization header with a token. In some other cases,
it could mean interpreting the challenge thrown by the server and then
making the same call again with a response to the challenge.

Can someone please help me understand this better?

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CABnk5p0k77he6c7Pw0APQJF%2B_FDJFOFdJp_BJ8eS66jbw6%3DG1w%40mail.gmail.com.


[go-nuts] http middleware and request context

2020-04-28 Thread Anuj Agrawal
Hi,

I have a situation where I have a chain of middlewares with a logger
middleware that comes before an authentication middleware. Logger
middleware logs about the incoming request, calls the next middleware
in the chain and then logs about the response. Authentication
middleware authenticates the incoming request and adds the
authenticated user to the request context (which ends up creating a
new request object to be passed downstream) before invoking the next
middleware.

Problem statement is that I want to log the authenticated user id in
the logger middleware. But because the request object known to the
logger middleware is not the same request object that the
authentication middleware set the user context with, I do not have the
user information available in the logger middleware.

I am deliberating on the ways of achieving this. Right now, I am
contemplating to add a pointer to a zero value struct with agreed upon
attributes (or with just a context attribute) or a map to the context
of the request object in logger middleware or an earlier middleware.
Then, in any downstream middleware I can set values of struct
attributes (or manipulate the context attribute) or set key value
pairs to the map. This makes the "context" being set by downstream
middlewares available to upstream middlewares after a downstream
middleware returns.

Are there better ways of doing it? Hopefully, others in the community
may have also faced similar problems and I would like to know about
any alternate ways that others may have used.

Thanks,
Anuj

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CABnk5p0H0YUm2vkL9Nb_CXVpgRy%2BJ87O6NH8FmgR5ewL4%3DSnsg%40mail.gmail.com.


Re: [go-nuts] Re: avoiding os thread creation due to logging

2018-08-06 Thread Anuj Agrawal
I am not sure if that is indeed a better solution. I am probably better off
delegating the responsibility of writing logs to a dedicated goroutine.

On Sun, Aug 5, 2018 at 10:51 PM,  wrote:

> You can use a semaphore-like pattern described in
> https://tip.golang.org/ref/mem to limit the number of goroutines trying
> to concurrently write to the log file. This remove the need for the
> buffering scheme.
>
>
> On Sunday, August 5, 2018 at 9:32:06 AM UTC-7, Anuj Agrawal wrote:
>>
>> I have an application with more than 50k goroutines. I pass a context to
>> each of these goroutines which contains a logger and that logger writes to
>> a file. At some point, the number of goroutines trying to write a log
>> peaked and my application crashed with - runtime: program exceeds
>> 1-thread limitfatal error: thread exhaustion.
>>
>> To provide a quick fix, I added a writer in between the logger and the
>> file writer which would buffer all logs in a channel and a separate
>> goroutine can then read from the channel and write to the file, thus,
>> avoiding having to create so many OS threads. Something like:
>>
>> type writer struct {
>> wg sync.WaitGroup
>> buffer chan []byte
>> outio.WriteCloser
>> pool   sync.Pool
>> }
>>
>> func (w *writer) Write(p []byte) (int, error) {
>> tmp := w.pool.Get().([]byte)
>> tmp = append(tmp[:0], p...)
>> w.buffer <- tmp
>> return len(tmp), nil
>> }
>>
>> go func() {
>> for p := range w.buffer {
>> if _, err := w.out.Write(p); err != nil {
>> log.Printf("error writing to log file: %s\n%s\n", err.Error(), string(p))
>> }
>> w.pool.Put(p)
>> }
>> w.wg.Done()
>> }()
>>
>>
>>
>> I want to have suggestions if it can be fixed in a better way.
>>
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [go-nuts] Re: How to reuse go fix tool code

2018-08-05 Thread Anuj Agrawal
ch only if they denote the same object.  This allows correct
> matching even in the presence of dot imports, named imports and
> locally shadowed package names in the input program.
>
> Matching of type syntax is semantic, not syntactic: type syntax in the
> pattern matches type syntax in the input if the types are identical.
> Thus, func(x int) matches func(y int).
>
> This tool was inspired by other example-based refactoring tools,
> 'gofmt -r' for Go and Refaster for Java.
>
>
> LIMITATIONS
> ===
>
> EXPRESSIVENESS
>
> Only refactorings that replace one expression with another, regardless
> of the expression's context, may be expressed.  Refactoring arbitrary
> statements (or sequences of statements) is a less well-defined problem
> and is less amenable to this approach.
>
> A pattern that contains a function literal (and hence statements)
> never matches.
>
> There is no way to generalize over related types, e.g. to express that
> a wildcard may have any integer type, for example.
>
> It is not possible to replace an expression by one of a different
> type, even in contexts where this is legal, such as x in fmt.Print(x).
>
> The struct literals T{x} and T{K: x} cannot both be matched by a single
> template.
>
>
> SAFETY
>
> Verifying that a transformation does not introduce type errors is very
> complex in the general case.  An innocuous-looking replacement of one
> constant by another (e.g. 1 to 2) may cause type errors relating to
> array types and indices, for example.  The tool performs only very
> superficial checks of type preservation.
>
>
> IMPORTS
>
> Although the matching algorithm is fully aware of scoping rules, the
> replacement algorithm is not, so the replacement code may contain
> incorrect identifier syntax for imported objects if there are dot
> imports, named imports or locally shadowed package names in the input
> program.
>
> Imports are added as needed, but they are not removed as needed.
> Run 'goimports' on the modified file for now.
>
> Dot imports are forbidden in the template.
>
>
> TIPS
> 
>
> Sometimes a little creativity is required to implement the desired
> migration.  This section lists a few tips and tricks.
>
> To remove the final parameter from a function, temporarily change the
> function signature so that the final parameter is variadic, as this
> allows legal calls both with and without the argument.  Then use eg to
> remove the final argument from all callers, and remove the variadic
> parameter by hand.  The reverse process can be used to add a final
> parameter.
>
> To add or remove parameters other than the final one, you must do it in
> stages: (1) declare a variant function f' with a different name and the
> desired parameters; (2) use eg to transform calls to f into calls to f',
> changing the arguments as needed; (3) change the declaration of f to
> match f'; (4) use eg to rename f' to f in all calls; (5) delete f'.
> 
>
> --thepudds
>
> On Friday, March 16, 2018 at 9:51:58 AM UTC-4, peterGo wrote:
>>
>> Anuj Agrawal,
>>
>> Exporting an API carries a commitment to maintain and support that API.
>> go fix was a special-purpose command, that was useful before the Go1
>> compatibility guarantee. I can see no reason to export a go fix API.
>> Peter
>>
>>
>> On Thursday, March 15, 2018 at 6:20:47 AM UTC-4, Anuj Agrawal wrote:
>>>
>>> Hi,
>>>
>>> I am looking to create a gofix for one of my projects. I thought of
>>> importing the code in
>>> https://github.com/golang/go/tree/master/src/cmd/fix so that I could
>>> simply write a plugin, build a binary and give it to people who import
>>> my code.
>>>
>>> However, I do not see any exported symbols in this code. That leaves
>>> me with only one choice - that I copy the code and then write the
>>> plugin on top of it. That does not sound like a very great idea as
>>> compared to being able to import the package itself.
>>>
>>> Is there any particular reason for not exporting any symbols in the
>>> gofix code?
>>>
>>> Thanks,
>>> Anuj Agrawal
>>>
>> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[go-nuts] avoiding os thread creation due to logging

2018-08-05 Thread Anuj Agrawal
I have an application with more than 50k goroutines. I pass a context to
each of these goroutines which contains a logger and that logger writes to
a file. At some point, the number of goroutines trying to write a log
peaked and my application crashed with - runtime: program exceeds
1-thread limitfatal error: thread exhaustion.

To provide a quick fix, I added a writer in between the logger and the file
writer which would buffer all logs in a channel and a separate goroutine
can then read from the channel and write to the file, thus, avoiding having
to create so many OS threads. Something like:

type writer struct {
wg sync.WaitGroup
buffer chan []byte
outio.WriteCloser
pool   sync.Pool
}

func (w *writer) Write(p []byte) (int, error) {
tmp := w.pool.Get().([]byte)
tmp = append(tmp[:0], p...)
w.buffer <- tmp
return len(tmp), nil
}

go func() {
for p := range w.buffer {
if _, err := w.out.Write(p); err != nil {
log.Printf("error writing to log file: %s\n%s\n", err.Error(), string(p))
}
w.pool.Put(p)
}
w.wg.Done()
}()



I want to have suggestions if it can be fixed in a better way.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[go-nuts] How to reuse go fix tool code

2018-03-15 Thread Anuj Agrawal
Hi,

I am looking to create a gofix for one of my projects. I thought of
importing the code in
https://github.com/golang/go/tree/master/src/cmd/fix so that I could
simply write a plugin, build a binary and give it to people who import
my code.

However, I do not see any exported symbols in this code. That leaves
me with only one choice - that I copy the code and then write the
plugin on top of it. That does not sound like a very great idea as
compared to being able to import the package itself.

Is there any particular reason for not exporting any symbols in the gofix code?

Thanks,
Anuj Agrawal

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[go-nuts] Re: [mysql] 2017/12/23 11:09:37 packets.go:141: write tcp 127.0.0.1:20630->127.0.0.1:3306: write: broken pipe

2017-12-27 Thread Anuj Agrawal
I am seeing similar logs even after I add db.SetConnMaxLifetime(10 * 
time.Second). 

Test code here: https://play.golang.org/p/itTUXDYv4Ge

Any suggestions on how to debug further?

On Monday, December 25, 2017 at 12:10:02 PM UTC+5:30, Naoki INADA wrote:
>
>
>>
>> To prevent further errors set connection lifetime to value less than 
>> configured.
>>
>>
>> eg. db.SetConnMaxLifetime(time.Second * 14400)
>>
>>
>>
> Thanks, but I (go-sql-driver/mysql maintainer) recommend 10~60 sec
> rather than 1/2 of wait_timeout.
>
> wait_timeout is not the only reason which close TCP connection.
> TCP connection may be killed by various reasons.  (OS, router, etc...)
>
> When people ask this question, they doesn't have enough skill to
> check all possibilities by themselves.
> On the other hand, 10sec is large enough to reduce overhead of
> reconnection.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.