FAQ
I've been doing some Ajax-y stuff with Go, and have run into a problem. I
have buttons in life.html that send events via GET
"/button?title=button_id", and the response comes back via a "long poll<http://en.wikipedia.org/wiki/Push_technology#Long_polling>"
XMLHttpRequest to GET "/updates". "/button" goes to Button(); "/updates"
goes to Updates(). Button() puts the response on a channel; Updates()
listens on the channel and sends it back as the response to the long poll.

So my problem is that when I hit "reload" on the main webpage, the "long
poll" of /updates is closed, and a new one is opened. But Updates()
doesn't realize this, and continues to wait on its channel. When you press
a button, and input does finally come in on the channel, Updates() sends it
out on the ResponseWriter, but it's the wrong ResponseWriter, it's the one
from before you pressed reload. So if you press reload once, the first
button press is ignored; if you press reload N times, the first N button
presses are ignored, eaten by the first N Updates() goroutines.

So my question is two-fold: Am I doing this Ajax-y thing entirely wrong?
And if not, how can I tell, in Updates(), that the connection has been
closed and I shouldn't try to write the response to the button-press on it?

Now, I realize that ideally I would keep track of what connection is
active, and send the response to the active query. Even in that case, I'd
still somehow like to be able to close down the Updates() goroutine(s)
that's now inactive; otherwise each reload would leak a goroutine.

The full repository is here: https://github.com/theclapp/go-life . Thank
you for your help!

-- Larry

--

Search Discussions

  • Steven Degutis at Sep 16, 2012 at 12:16 am
    Slightly off topic but you may want to consider renaming your account name
    on github so it's not an alias for gonorrhea.

    -Steven

    On Saturday, September 15, 2012 7:09:24 PM UTC-5, Larry Clapp wrote:

    I've been doing some Ajax-y stuff with Go, and have run into a problem. I
    have buttons in life.html that send events via GET
    "/button?title=button_id", and the response comes back via a "long poll<http://en.wikipedia.org/wiki/Push_technology#Long_polling>"
    XMLHttpRequest to GET "/updates". "/button" goes to Button(); "/updates"
    goes to Updates(). Button() puts the response on a channel; Updates()
    listens on the channel and sends it back as the response to the long poll.

    So my problem is that when I hit "reload" on the main webpage, the "long
    poll" of /updates is closed, and a new one is opened. But Updates()
    doesn't realize this, and continues to wait on its channel. When you press
    a button, and input does finally come in on the channel, Updates() sends it
    out on the ResponseWriter, but it's the wrong ResponseWriter, it's the one
    from before you pressed reload. So if you press reload once, the first
    button press is ignored; if you press reload N times, the first N button
    presses are ignored, eaten by the first N Updates() goroutines.

    So my question is two-fold: Am I doing this Ajax-y thing entirely wrong?
    And if not, how can I tell, in Updates(), that the connection has been
    closed and I shouldn't try to write the response to the button-press on it?

    Now, I realize that ideally I would keep track of what connection is
    active, and send the response to the active query. Even in that case, I'd
    still somehow like to be able to close down the Updates() goroutine(s)
    that's now inactive; otherwise each reload would leak a goroutine.

    The full repository is here: https://github.com/theclapp/go-life . Thank
    you for your help!

    -- Larry
    --
  • Larry Clapp at Sep 16, 2012 at 12:57 am
    :) That's part of its charm. I own theclapp.org, too.

    Does Google Groups (et al) not show that my last name is Clapp?

    That said, if you really honestly think it's broadly offensive, I'm willing
    to change it.

    -- Larry

    On Saturday, September 15, 2012 8:16:14 PM UTC-4, Steven Degutis wrote:

    Slightly off topic but you may want to consider renaming your account name
    on github so it's not an alias for gonorrhea.

    -Steven

    On Saturday, September 15, 2012 7:09:24 PM UTC-5, Larry Clapp wrote:

    I've been doing some Ajax-y stuff with Go, and have run into a problem.
    I have buttons in life.html that send events via GET
    "/button?title=button_id", and the response comes back via a "long poll<http://en.wikipedia.org/wiki/Push_technology#Long_polling>"
    XMLHttpRequest to GET "/updates". "/button" goes to Button(); "/updates"
    goes to Updates(). Button() puts the response on a channel; Updates()
    listens on the channel and sends it back as the response to the long poll.

    So my problem is that when I hit "reload" on the main webpage, the "long
    poll" of /updates is closed, and a new one is opened. But Updates()
    doesn't realize this, and continues to wait on its channel. When you press
    a button, and input does finally come in on the channel, Updates() sends it
    out on the ResponseWriter, but it's the wrong ResponseWriter, it's the one
    from before you pressed reload. So if you press reload once, the first
    button press is ignored; if you press reload N times, the first N button
    presses are ignored, eaten by the first N Updates() goroutines.

    So my question is two-fold: Am I doing this Ajax-y thing entirely wrong?
    And if not, how can I tell, in Updates(), that the connection has been
    closed and I shouldn't try to write the response to the button-press on it?

    Now, I realize that ideally I would keep track of what connection is
    active, and send the response to the active query. Even in that case, I'd
    still somehow like to be able to close down the Updates() goroutine(s)
    that's now inactive; otherwise each reload would leak a goroutine.

    The full repository is here: https://github.com/theclapp/go-life .
    Thank you for your help!

    -- Larry
    --
  • Patrick Mylund Nielsen at Sep 16, 2012 at 12:59 am
    The clapp is going nuts on this list.
    On Sun, Sep 16, 2012 at 2:57 AM, Larry Clapp wrote:

    :) That's part of its charm. I own theclapp.org, too.

    Does Google Groups (et al) not show that my last name is Clapp?

    That said, if you really honestly think it's broadly offensive, I'm
    willing to change it.

    -- Larry

    On Saturday, September 15, 2012 8:16:14 PM UTC-4, Steven Degutis wrote:

    Slightly off topic but you may want to consider renaming your account
    name on github so it's not an alias for gonorrhea.

    -Steven

    On Saturday, September 15, 2012 7:09:24 PM UTC-5, Larry Clapp wrote:

    I've been doing some Ajax-y stuff with Go, and have run into a problem.
    I have buttons in life.html that send events via GET
    "/button?title=button_id", and the response comes back via a "long poll<http://en.wikipedia.org/wiki/Push_technology#Long_polling>"
    XMLHttpRequest to GET "/updates". "/button" goes to Button(); "/updates"
    goes to Updates(). Button() puts the response on a channel; Updates()
    listens on the channel and sends it back as the response to the long poll.

    So my problem is that when I hit "reload" on the main webpage, the "long
    poll" of /updates is closed, and a new one is opened. But Updates()
    doesn't realize this, and continues to wait on its channel. When you press
    a button, and input does finally come in on the channel, Updates() sends it
    out on the ResponseWriter, but it's the wrong ResponseWriter, it's the one
    from before you pressed reload. So if you press reload once, the first
    button press is ignored; if you press reload N times, the first N button
    presses are ignored, eaten by the first N Updates() goroutines.

    So my question is two-fold: Am I doing this Ajax-y thing entirely wrong?
    And if not, how can I tell, in Updates(), that the connection has been
    closed and I shouldn't try to write the response to the button-press on it?

    Now, I realize that ideally I would keep track of what connection is
    active, and send the response to the active query. Even in that case, I'd
    still somehow like to be able to close down the Updates() goroutine(s)
    that's now inactive; otherwise each reload would leak a goroutine.

    The full repository is here: https://github.com/**theclapp/go-life<https://github.com/theclapp/go-life>. Thank you for your help!

    -- Larry

    --
    --
  • Patrick Mylund Nielsen at Sep 16, 2012 at 1:06 am
    (I don't think anyone thinks it's offensive :))
    On Sun, Sep 16, 2012 at 2:59 AM, Patrick Mylund Nielsen wrote:

    The clapp is going nuts on this list.

    On Sun, Sep 16, 2012 at 2:57 AM, Larry Clapp wrote:

    :) That's part of its charm. I own theclapp.org, too.

    Does Google Groups (et al) not show that my last name is Clapp?

    That said, if you really honestly think it's broadly offensive, I'm
    willing to change it.

    -- Larry

    On Saturday, September 15, 2012 8:16:14 PM UTC-4, Steven Degutis wrote:

    Slightly off topic but you may want to consider renaming your account
    name on github so it's not an alias for gonorrhea.

    -Steven

    On Saturday, September 15, 2012 7:09:24 PM UTC-5, Larry Clapp wrote:

    I've been doing some Ajax-y stuff with Go, and have run into a problem.
    I have buttons in life.html that send events via GET
    "/button?title=button_id", and the response comes back via a "long poll<http://en.wikipedia.org/wiki/Push_technology#Long_polling>"
    XMLHttpRequest to GET "/updates". "/button" goes to Button(); "/updates"
    goes to Updates(). Button() puts the response on a channel; Updates()
    listens on the channel and sends it back as the response to the long poll.

    So my problem is that when I hit "reload" on the main webpage, the
    "long poll" of /updates is closed, and a new one is opened. But Updates()
    doesn't realize this, and continues to wait on its channel. When you press
    a button, and input does finally come in on the channel, Updates() sends it
    out on the ResponseWriter, but it's the wrong ResponseWriter, it's the one
    from before you pressed reload. So if you press reload once, the first
    button press is ignored; if you press reload N times, the first N button
    presses are ignored, eaten by the first N Updates() goroutines.

    So my question is two-fold: Am I doing this Ajax-y thing entirely
    wrong? And if not, how can I tell, in Updates(), that the connection has
    been closed and I shouldn't try to write the response to the button-press
    on it?

    Now, I realize that ideally I would keep track of what connection is
    active, and send the response to the active query. Even in that case, I'd
    still somehow like to be able to close down the Updates() goroutine(s)
    that's now inactive; otherwise each reload would leak a goroutine.

    The full repository is here: https://github.com/**theclapp/go-life<https://github.com/theclapp/go-life>. Thank you for your help!

    -- Larry

    --
    --
  • Kyle Lemons at Sep 16, 2012 at 12:59 am
    Back on topic...

    You will have to hijack the connection if you want to know when it is
    closed. You can have the writer and the waiter on separate goroutines, so
    that they are both waiting for their respective action to happen.
    On Sat, Sep 15, 2012 at 5:09 PM, Larry Clapp wrote:

    I've been doing some Ajax-y stuff with Go, and have run into a problem. I
    have buttons in life.html that send events via GET
    "/button?title=button_id", and the response comes back via a "long poll<http://en.wikipedia.org/wiki/Push_technology#Long_polling>"
    XMLHttpRequest to GET "/updates". "/button" goes to Button(); "/updates"
    goes to Updates(). Button() puts the response on a channel; Updates()
    listens on the channel and sends it back as the response to the long poll.

    So my problem is that when I hit "reload" on the main webpage, the "long
    poll" of /updates is closed, and a new one is opened. But Updates()
    doesn't realize this, and continues to wait on its channel. When you press
    a button, and input does finally come in on the channel, Updates() sends it
    out on the ResponseWriter, but it's the wrong ResponseWriter, it's the one
    from before you pressed reload. So if you press reload once, the first
    button press is ignored; if you press reload N times, the first N button
    presses are ignored, eaten by the first N Updates() goroutines.

    So my question is two-fold: Am I doing this Ajax-y thing entirely wrong?
    And if not, how can I tell, in Updates(), that the connection has been
    closed and I shouldn't try to write the response to the button-press on it?

    Now, I realize that ideally I would keep track of what connection is
    active, and send the response to the active query. Even in that case, I'd
    still somehow like to be able to close down the Updates() goroutine(s)
    that's now inactive; otherwise each reload would leak a goroutine.

    The full repository is here: https://github.com/theclapp/go-life . Thank
    you for your help!

    -- Larry

    --

    --
  • Jorelli at Sep 18, 2012 at 6:22 pm
    another potential solution, instead of worrying about connection hijacking,
    is to add some kind of progress parameter to your polling call, generally a
    timestamp or incremental ID. Since you're writing Conway's game of life,
    you probably want to number your generations and have the client send the
    generation number that it has last recorded, and have the server serve the
    following generation (or generations).

    looking at your repository, I strongly recommend using jQuery over doing
    the XMLHttpRequest boilerplate by hand. They've got all that cross-browser
    boilerplate figured out, and the API is much nicer.

    I have a long-polling chatroom app that uses jQuery here, if you want to
    use it for reference: https://github.com/jordanorelli/gochat

    but it's really old and it's one of the first things I wrote in Go; I think
    it has the same problem you're describing, so I can't honestly say it's of
    good quality. I don't know that I've even run it since Go1 came out. But
    it's longpolling between javascript and Go, using jQuery, nonetheless.


    best of luck on your project

    -jordan

    On Saturday, September 15, 2012 8:09:24 PM UTC-4, Larry Clapp wrote:

    I've been doing some Ajax-y stuff with Go, and have run into a problem. I
    have buttons in life.html that send events via GET
    "/button?title=button_id", and the response comes back via a "long poll<http://en.wikipedia.org/wiki/Push_technology#Long_polling>"
    XMLHttpRequest to GET "/updates". "/button" goes to Button(); "/updates"
    goes to Updates(). Button() puts the response on a channel; Updates()
    listens on the channel and sends it back as the response to the long poll.

    So my problem is that when I hit "reload" on the main webpage, the "long
    poll" of /updates is closed, and a new one is opened. But Updates()
    doesn't realize this, and continues to wait on its channel. When you press
    a button, and input does finally come in on the channel, Updates() sends it
    out on the ResponseWriter, but it's the wrong ResponseWriter, it's the one
    from before you pressed reload. So if you press reload once, the first
    button press is ignored; if you press reload N times, the first N button
    presses are ignored, eaten by the first N Updates() goroutines.

    So my question is two-fold: Am I doing this Ajax-y thing entirely wrong?
    And if not, how can I tell, in Updates(), that the connection has been
    closed and I shouldn't try to write the response to the button-press on it?

    Now, I realize that ideally I would keep track of what connection is
    active, and send the response to the active query. Even in that case, I'd
    still somehow like to be able to close down the Updates() goroutine(s)
    that's now inactive; otherwise each reload would leak a goroutine.

    The full repository is here: https://github.com/theclapp/go-life . Thank
    you for your help!

    -- Larry
    --
  • Larry Clapp at Sep 19, 2012 at 12:12 am
    Jordan,

    Thank you, that's good advice. I've looked at jQuery and think it looks
    really neat, and I'd probably use it in a real-world project. For my Life
    game, this is, as I said in another thread, the most sophisticated web
    programming I've done, and I wanted to do it "the hard way", on the theory
    that by writing it myself I'd get a better understanding of some of the
    issues involved.

    The route I've decided to take, at least for the moment, is to keep a list
    of all listeners, and not to care if any given connection is open or not.
    Every event for a particular session goes back to every listener, so of
    one of those listeners has closed the connection, the goroutine gets
    cleaned up, and for any that are still alive, they all get the event. If
    you press reload, or open a new window, I push an empty event back to all
    listeners, and so again any dead connections (and their associated
    goroutines) will thus just go away essentially on their own.

    Thanks again for your response, and for doing me the honor of looking at my
    code! :)

    -- Larry

    On Tuesday, September 18, 2012 2:22:29 PM UTC-4, jorelli wrote:

    another potential solution, instead of worrying about connection
    hijacking, is to add some kind of progress parameter to your polling call,
    generally a timestamp or incremental ID. Since you're writing Conway's
    game of life, you probably want to number your generations and have the
    client send the generation number that it has last recorded, and have the
    server serve the following generation (or generations).

    looking at your repository, I strongly recommend using jQuery over doing
    the XMLHttpRequest boilerplate by hand. They've got all that cross-browser
    boilerplate figured out, and the API is much nicer.

    I have a long-polling chatroom app that uses jQuery here, if you want to
    use it for reference: https://github.com/jordanorelli/gochat

    but it's really old and it's one of the first things I wrote in Go; I
    think it has the same problem you're describing, so I can't honestly say
    it's of good quality. I don't know that I've even run it since Go1 came
    out. But it's longpolling between javascript and Go, using jQuery,
    nonetheless.


    best of luck on your project

    -jordan

    On Saturday, September 15, 2012 8:09:24 PM UTC-4, Larry Clapp wrote:

    I've been doing some Ajax-y stuff with Go, and have run into a problem.
    I have buttons in life.html that send events via GET
    "/button?title=button_id", and the response comes back via a "long poll<http://en.wikipedia.org/wiki/Push_technology#Long_polling>"
    XMLHttpRequest to GET "/updates". "/button" goes to Button(); "/updates"
    goes to Updates(). Button() puts the response on a channel; Updates()
    listens on the channel and sends it back as the response to the long poll.

    So my problem is that when I hit "reload" on the main webpage, the "long
    poll" of /updates is closed, and a new one is opened. But Updates()
    doesn't realize this, and continues to wait on its channel. When you press
    a button, and input does finally come in on the channel, Updates() sends it
    out on the ResponseWriter, but it's the wrong ResponseWriter, it's the one
    from before you pressed reload. So if you press reload once, the first
    button press is ignored; if you press reload N times, the first N button
    presses are ignored, eaten by the first N Updates() goroutines.

    So my question is two-fold: Am I doing this Ajax-y thing entirely wrong?
    And if not, how can I tell, in Updates(), that the connection has been
    closed and I shouldn't try to write the response to the button-press on it?

    Now, I realize that ideally I would keep track of what connection is
    active, and send the response to the active query. Even in that case, I'd
    still somehow like to be able to close down the Updates() goroutine(s)
    that's now inactive; otherwise each reload would leak a goroutine.

    The full repository is here: https://github.com/theclapp/go-life .
    Thank you for your help!

    -- Larry
    --

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedSep 16, '12 at 12:09a
activeSep 19, '12 at 12:12a
posts8
users5
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase