Maxim Yefremov
Maxim Yefremov

Reputation: 14185

slack integration: 404 Expired url https://hooks.slack.com/commands

Here is my golang app listening requests from slack command: main.go:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "time"
)

type SlackCmdResponse struct {
    Text string `json:"text"`
}

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        if err := req.ParseForm(); err != nil {
            panic(err)
        }
        responseUrl := req.PostFormValue("response_url")
        go func() {
            time.Sleep(time.Second)
            postBack(responseUrl)
        }()
        rj, err := json.Marshal(SlackCmdResponse{Text: "Test started"})
        if err != nil {
            panic(err)
        }
        w.Header().Set("Content-Type", "application/json")
        w.Write(rj)

    })
    fmt.Println("listening 8383")
    if err := http.ListenAndServe(":8383", nil); err != nil {
        panic(err)
    }
}

func postBack(responseUrl string) {
    fmt.Println("responseUrl", responseUrl)
    cResp := SlackCmdResponse{
        Text: "Test finished",
    }
    cj, err := json.Marshal(cResp)
    if err != nil {
        panic(err)
    }
    req, err := http.NewRequest("POST", responseUrl, bytes.NewReader(cj))
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    if resp != nil {
        fmt.Println(resp.StatusCode)
        if b, err := ioutil.ReadAll(resp.Body); err != nil {
            panic(err)
        } else {
            fmt.Println(string(b))
        }
        if resp.Body != nil {
            resp.Body.Close()
        }
    }
}

I run it:

$ go run main.go
listening 8383

I use ngrok to make it accessible from the internet:

ngrok http 8383

I created slack slash command /my-command with POST option and pasted https URL that ngrok gave:

slash command options - slack

Now when I run /my-command in slack, I get slack reply Test started. And then in a second slack prints Test finished

For now, it's all fine.

Problem

If I replace line

time.Sleep(time.Second)

by line

time.Sleep(time.Hour) // long test

I don't get slack printed "Test finished" in hour. Instead, I see in my app logs:

responseUrl https://hooks.slack.com/commands/T3GBFUZ64/86817661808/XRmDO21jYaP1Wzu7GFpNw9eW
404
Expired url

Looks like slack's response URL has an expiration time. How to extend this expiration time?

Or in a case of expiration, is there another way to send a message to the user about having the test finished? I have name and id of a user launching /my-command

req.PostFormValue("user_name")
req.PostFormValue("user_id")

So I want to run integration tests by slack which are longer than 2 hours and get a response after finishing such tests in slack.

Upvotes: 4

Views: 2001

Answers (1)

dmportella
dmportella

Reputation: 4724

You can not increase the expire time for the URL that is a Slack internal setting.

Using the Slack Web API

You can send unattended messages to any user through the Slack Web API which you need a token for it.

For more information check: https://api.slack.com/web.

chat.postMessage

The Slack API has a postMessage command that allows the user to post messages to a channel, to the slackbot channel and to the user through IM channel (direct message). It seems you want to do the later which is quite simple.

Post to an IM channel

chat.postMessage#channels

Method Url: https://slack.com/api/chat.postMessage

Posting to an IM channel is a little more complex when settings the value of channel depending on the value of as_user.

  • If as_user is false:
    • Pass a username (@chris) as the value of channel to post to that user's @slackbot channel as the bot.
    • Pass the IM channel's ID (D023BB3L2) as the value of channel to post to that IM channel as the bot. The IM channel's ID can be retrieved through the im.list API method.
  • If as_user is true:
    • Pass the IM channel's ID (D023BB3L2) as the value of channel to post to that IM channel as the authenticated user. The IM channel's ID can be retrieved through the im.list API method. To send a direct message to the user owning the token used in the request, provide the channel field with the a conversation/IM ID value found in a method like im.list.

To send a direct message to the user owning the token used in the request, provide the channel field with the a conversation/IM ID value found in a method like im.list.

im.list

This method will return a list of direct messages channels if you don't have a channel open with the user yet you can call the im.open.

im.open

This method is used to open a direct message channel with a specified user.

Documentation about im.open can be found here.

Example URL

https://slack.com/api/chat.postMessage?token=**TOKEN**&channel=**Direct Channel ID**&text=HelloWorld&as_user=true&pretty=1

Just replace **TOKEN** and **Direct Channel ID** with your values and it should send a direct message to the specified user.

Upvotes: 4

Related Questions