Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Go + Google Cloud Functions を使ったSlackのThreadにも対...
Search
ktykogm
July 25, 2019
Programming
0
430
Go + Google Cloud Functions を使ったSlackのThreadにも対応したbotを簡単に作る方法
Slack Dev Meetup Tokyo #1 LT 資料です。
ktykogm
July 25, 2019
Tweet
Share
More Decks by ktykogm
See All by ktykogm
街じゅうを"駅前化"する電動マイクロモビリティのシェアサービス「LUUP」のIoTとSRE
0gm
2
11k
サービスと組織の拡大を支えるEmbedded SREs
0gm
7
3.5k
SRE的team開発Tipsとベストプラクティスっぽい何か
0gm
9
5.2k
Other Decks in Programming
See All in Programming
SwiftUI移行のためのインプレッショントラッキング基盤の構築
kokihirokawa
0
120
kintone開発を効率化するためにチームで試した施策とその結果を大放出!
oguemon
0
170
PHPカンファレンス名古屋2025 タスク分解の試行錯誤〜レビュー負荷を下げるために〜
soichi
1
680
もう僕は OpenAPI を書きたくない
sgash708
6
1.9k
なぜイベント駆動が必要なのか - CQRS/ESで解く複雑系システムの課題 -
j5ik2o
14
4.7k
From the Wild into the Clouds - Laravel Meetup Talk
neverything
0
160
CloudNativePGを布教したい
nnaka2992
0
110
.NET Frameworkでも汎用ホストが使いたい!
tomokusaba
0
200
苦しいTiDBへの移行を乗り越えて快適な運用を目指す
leveragestech
0
1.1k
クリーンアーキテクチャから見る依存の向きの大切さ
shimabox
5
1.1k
密集、ドキュメントのコロケーション with AWS Lambda
satoshi256kbyte
1
210
Jakarta EE meets AI
ivargrimstad
0
450
Featured
See All Featured
How to Ace a Technical Interview
jacobian
276
23k
Building an army of robots
kneath
303
45k
Gamification - CAS2011
davidbonilla
80
5.2k
Optimising Largest Contentful Paint
csswizardry
34
3.1k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
114
50k
Unsuck your backbone
ammeep
669
57k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.3k
Faster Mobile Websites
deanohume
306
31k
What's in a price? How to price your products and services
michaelherold
244
12k
The Invisible Side of Design
smashingmag
299
50k
Raft: Consensus for Rubyists
vanstee
137
6.8k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Transcript
(P (PPHMF$MPVE'VODUJPOTΛͬ ͨ4MBDLͷUISFBEʹରԠͨ͠CPUΛ؆ ୯ʹ࡞Δํ๏ λΠτϧ͕͗ͨ͢LUZLPHN 4MBDL%FW.FFUVQ5PLZP-5ࢿྉ
XIPBNJ w !LUZLPHN LPHVNB w ϝϧΧϦ43& w ࠷ۙ(PΛۀͰͨ·ʹॻ͍͍ͯΔϨϕϧ w
ʮ4MBDL (PͳΒͦͷ͘Β͍؆୯ʹԼ४උͰ͖ΔΑʯͱ͍͏͜ͱΛ ͑ʹདྷ·ͨ͠ w 43&-PVOHFͱ͍͏ίϛϡχςΟͷӡӦ׆ಈΛ͍ͯ͠·͢ɻ
ຊ͍͑ͨ͜ͱ w 4MBDL (P $MPVE'VODUJPOTͷ૬ੑ w (PΛͬͨ4MBDLͷ5ISFBEରԠํ๏ w (Pք۾ͰΑ͘ΒΕͨOMPQFTTMBDL͕DPPPPPPPPM w
ͦΕΒ#PU ͦΕҎ֎ ࡞ɺαʔόͱӡ༻අΛ༻ҙͤͣʹؾָʹ࢝Ί ΒΕΔ
$MPVE'VODUJPOTͱ w ΠϕϯτυϦϒϯͳαʔόϨείϯϐϡʔτϓϥοτ ϑΥʔϜ w (BUFXBZແͯ͘ಈ͘ w &YUFOTJCMF4FSWJDF1SPYZ &41 Λͬͯ(BUFXBZ
FOEQPJOUߏͪΖΜͰ͖·͢ɻ w ͦͷ··ؔΛઃஔͰ͖Δ HPCVJMEෆཁ w ࣗಈతʹεέʔϧͭɺ)" w ଞͷ($1αʔϏεʹଓ֦ͯ͠ு͕Մೳ w ແྉ͕ଘࡏ͢Δ w ݄ؒͰɺສݺͼग़͠ ສඵ (#ԼΓτϥ ϑΟοΫ ݄ʹ(PSVUJNF͕CFUBSFMFBTF IUUQTDMPVEHPPHMFDPNGVODUJPOT
$MPVE'VODUJPOT ଞͷ($1αʔϏεʹଓ֦ͯ͠ு͕Մೳ w $MPVE1VC4VC w $MPVE4UPSBHF w )551 w 4UBDLESJWFS-PHHJOH
w 'JSFCBTF w $MPVE42- $POOFDU71$ FUD
ࣄલ४උ w 4MBDLͷ༻ҙ w (PPHMF$MPVE1MBUGPSN ($1 ͷΞΧϯτΛ࡞ w HDMPVEίϚϯυ͕͑ΔΑ͏ʹ(PPHMF$MPVE4%,Λ*OTUBMM w
IUUQTDMPVEHPPHMFDPNTELJOTUBMM w HDMPVEݱࡏ1ZUIPO͕ඞཁͳͷͰɺQZFOWͰXPSLJOH EJSFDUPSZʹQZFOWMPDBMYͰཧ͢Δͱྑ͍Ͱ͢
ࠓճͷߏͱڥʹ͍ͭͯ w ࠓճ-5ͳͷͰλΠτϧʹ͋Δ4MBDL5ISFBEʹରԠͨ͠#PUΛ࡞͢Δ ํ๏ͱͦͷઆ໌͚ͩʹ༰Λ΄΅ߜΓ·͢ w 4MBDLࣗମ4MBTI$PNNBOE#PUͷNFOUJPOʹΑΔԠͳͲ༷ʑ ͳํͰରԠͰ͖·͢ w 4MBDLͷ35."1*Λ༻ w
(PͷOMPQFTTMBDLNPEVMFΛ༻
࠷খ$PEF package gcf_slack_sample import ( "net/http" "os" "strings" "github.com/nlopes/slack" )
var ( threadTs slack.RTMsgOption ) type SlackParams struct { accessToken string botUserID string rtm *slack.RTM } func PostMessage(w http.ResponseWriter, r *http.Request) { // Ҿ০ΓɻCloud Functionͷhttp trigger Ͱඞཁ params := SlackParams{ accessToken: os.Getenv("ACCESS_TOKEN"), botUserID: "", } api := slack.New(params.accessToken) params.rtm = api.NewRTM() go params.rtm.ManageConnection() go func() { for msg := range params.rtm.IncomingEvents { switch ev := msg.Data.(type) { case *slack.ConnectedEvent: params.botUserID = ev.Info.User.ID case *slack.MessageEvent: if !strings.Contains(ev.Msg.Text, params.botUserID) { continue } threadTs = slack.RTMsgOptionTS(ev.ThreadTimestamp) params.rtm.SendMessage(params.rtm.NewOutgoingMessage("Sample TEST", ev.Channel, threadTs)) } } }() ࣮͜Ε͚ͩͰɺຊ ͷʮ4MBDLͷ5ISFBEʹ ରԠͨ͠#PUPO $MPVE'VODUJPOTΛ(P Ͱ࡞Δʯ͜ͱՄೳ WBSTZBNMߦ͚ͩ$SFEFOUJBMཧ Ͱผ్͋Γ·͢ɻޙ΄Ͳઆ໌ HPNPEVMFTͷTFUVQͷઆ໌ল͖ ·͢
தͷઆ໌
FOEQPJOUؔ w (PPHMF$MPVE'VODUJPOTͷ༷ ͰɺNBJOؔҎ֎͕ඞཁʹͳΓ· ͢ɻ w ྫͰɺ1PTU.FTTBHF w Ͳ͔͜Β։࢝͞ΕΔ͔Θ͔Γ͍͢Α
͏ʹNBJOHPGVODUJPOHPͱ͍͏ pMF໊ʹͯ͠ҎԼͷΑ͏ʹ։࢝͢Δؔ Λ࡞Γ·͢ package gcf_slack_sample // <= ࣮ԿͰok // ..<snip> func PostMessage(w http.ResponseWriter, r *http.Request) { // Ҿ০ΓɻCloud Functionͷhttp trigger Ͱඞཁ params := SlackParams{ accessToken: os.Getenv("ACCESS_TOKEN"), botUserID: "", }
4MBDLͷ5ISFBEରԠ w TMBDL35.TH0QUJPO w ͜Εޙʹઆ໌͢Δ35.TH0QUJPO54 FW5ISFBE5JNFTUBNQ ʹؔ͠ ·͢ɻ var (
threadTs slack.RTMsgOption )
4MBDLͷ5ISFBEରԠ ҎԼ͕4MBDLͷ5ISFBEͰͦͷ࣌ʹऔಘ͞ΕΔ5ISFBE5JNF4UBNQΛ࣋ͪ· ͢ ͜ͷ5ISFBE5JNF4UBNQΛར༻͢Δ͜ͱͰ#PU͕4MBDLͷ5ISFBEʹରԠ͢ ΔΑ͏ʹͳΓ·͢ threadTs = slack.RTMsgOptionTS(ev.ThreadTimestamp)
4MBDLͷ5ISFBEରԠ 35.TH0QUJPO54 FW5ISFBE5JNFTUBNQ ͱԿͳͷ͔ go func() { for msg :=
range s.rtm.IncomingEvents { switch ev := msg.Data.(type) { ͜ͷFWɺͦͷલͷ35.ͷ*ODPNJOH&WFOUT͔Β&WFOUUZQF͝ͱʹTXJUDI͠ɺͦͷ&WFOUEBUBΛFWʹೖΕ͍ͯ·͢ case *slack.MessageEvent: // .. <snip> threadTs = slack.RTMsgOptionTS(ev.ThreadTimestamp) .FTTBHF&WFOUΛड͚औͬͨλΠϛϯάͰɺͦͷૹ৴ݩͷTMBDLͷUISFBEʹରԠ͢ΔͨΊʹ ͦͷ࣌ͷ5ISFBE5JNF4UBNQΛ༻͠·͢ ͢ͳΘͪɺ͜ͷ.FTTBHF&WFOU͕࢝·ͬͨ࣌ͷ5ISFBE5JNFTUBNQ͕ೖΓ·͢ɻ
OMPQFTTMBDLଆͷྲྀΕ ϖʔδͷ্ؔɺOMPQFTTMBDLଆͷઆ໌ׂѪ͠·͕͢ྲྀΕ͚ͩॻ͘ͱҎԼͰ͢ɻ 35.TH0QUJPO54 Ͱɺ.FTTBHF&WFOUΛड͚औͬͨͱ͖ͷ5ISFBE5NFTUBNQΛૹΔ 0VUHPJOH.FTTBBHF\5ISFBE5JNFTUBNQUISFBE5JNFTUBNQ^ʹઃఆ͞ΕΔ 35.TH0QUJPOܕͰฦ͢ 1BDLBHFWBSJBCMFͰࢦఆͨ͠มUISFBE5Tɺͦͷ35.TH0QUJPOܕͱͳΔ IUUQTHJUIVCDPNOMPQFTTMBDLCMPCFBFDEFFCDEEGD
NFTTBHFTHP--
ड͚औͬͨ5ISFBE5JNF4UBNQΛ͏ s.rtm.NewOutgoingMessage() ͜ͷؔɺTMBDL35.ͰҎԼͷΑ͏ʹఆٛ͞Ε͍ͯ·͢ɻ func (rtm *RTM) NewOutgoingMessage(text string, channelID string,
options ...RTMsgOption) *OutgoingMessage { // ..<snip> return &msg 4MBDLͰ#PU͕͢.FTTBHFΛೖΕΔؔ
ड͚औͬͨ5ISFBE5JNF4UBNQΛ͏ ҎԼͰUISFBE5JNF4UBNQΛ0QUJPOͰࢦఆ͢Εྑ͍Θ͚Ͱ͢ɻ s.rtm.NewOutgoingMessage(message, ev.Channel, threadTs)
ड͚औͬͨ5ISFBE5JNF4UBNQΛ͏ s.rtm.SendMessage(s.rtm.NewOutgoingMessage(message, ev.Channel, threadTs)) ࣮ࡍʹ.FTTBHFΛૹΔͨΊʹҎԼͷΑ͏ʹ͠·͢ɻ
͜ΕΛ$MPVE'VODUJPOTʹͤ ͯ4MBDLCPUͱͯ͠ొ͢Δ
4MBDLͰઃఆ 4MBDL"QQͷ࡞ɺొ͔Βɻ wิ w֤छͷઆ໌ʹ͍ͭͯҎԼ͕Θ͔Γ͍͢Ͱ͢ wIUUQTRJJUBDPNOBNVUBLBJUFNT BDBG IUUQTBQJTMBDLDPNBQQTɹΛ։͖·͢
4MBDLͰઃఆ $SFBUF/FX"QQTΛ։ ͍ͯ࡞Λ։࢝͠·͢ ͜͜ͰUFTUCPUͱ͍͏໊ લͰొ͠·͢ %FWFMPQNFOU4MBDL 8PSLTQBDFΛબ͠·͢
4MBDLͰઃఆ #PU6TFSTΛΫϦοΫ͠ ͯɺ"EEB#PUVTFSΛΫ ϦοΫ %JTQMBZOBNFͱ%FGBVMU VTFSOBNFͰɺͲͷΑ͏ ͳจࣈͰϋΠϑϯແ͠ ʹม͞ΕΔ
ϋΠϑϯ͕ඞཁͩͬͨΒՃ͍ͯͩ͘͠͞ VTFSOBNFจࣈ·Ͱͷ੍ݶ͕͋Γ· ͢ɻ
4MBDLͰઃఆ 4DPQFTʹ DIBUXSJUFCPUΛՃ͢Δ 4BWF$IBOHFTͰอଘ ಉ͡ϖʔδͷҰ൪্ʹ͋Δ
A*OTUBMMBQQUPXPSLTQBDFAΛ ΫϦοΫͯ͠"VUIPSJ[FE͢Δɻ 0BVUI1FSNJTTJPOTઃఆ
4MBDLͰઃఆ #PU6TFS0"VUI"DDFTT5PLFOΛऔ ಘͯ͠ɺWBSTZBNMʹॻ͘ 0BVUI1FSNJTTJPOTઃఆ ACCESS_TOKEN: xoxb-XXXXXXXXXXXXXXXXXXXX WBSTZBNM HJUJHOPSFʹೖΕ͓͖ͯ·͢
(PPHMF$MPVE'VODUJPOTʹEFQMPZ HDMPVEGVODUJPOTEFQMPZUFTUCPUa FOUSZQPJOU1PTU.FTTBHFa SVOUJNFHPa FOWWBSTpMFWBSTZBNMa USJHHFSIUUQ
(PPHMF$MPVE'VODUJPOTʹEFQMPZ ͠Βͭ͘ͱEFQMPZ͕ྃ͠·͢ɻ IUUQT5SJHHFS VSMIUUQTSFHJPOQSPKFDUDMPVEGVODUJPOTOFUUFTUCPU TUBUVT"$5*7& ͷΑ͏ͳIUUQT5SJHHFS͕ൃߦ͞Ε·͢ͷͰɺ͜ΕΛΫϦοΫ͠·͢ɻ
͜Ε͚ͩͰྃͰ͢ TMBDLͷDIBOOFMʹ#PUΛ*OWJUF͠·͢ɻ
#PUΛݺͼग़͢
#PUΛݺͼग़͢ 5ISFBEʹ#PUͷ .FOUJPOΛඈ͢ͱͦͷ 5ISFBEʹରԠ͍ͯ͠· ͢ɻ ·ͨɺ5ISFBEҎ֎ʹ ͦͷDIBOOFMʹਖ਼֬ʹ #PU͕ԠΛฦ͍ͤͯ· ͢ɻ
ิ w ͪΖΜࠓճ-5Ͱઆ໌༻Ͱۃʹͨ͘͠$PEFͰ͢ w ࣮ࡍʹ͏ͱ͖ظӡ༻Λߟ͑ͯॺ໊ͳΜ͔͚ͭΔͱྑ͍ͱࢥ͍·͢ w 4JHOJOHTFDSFU
·ͱΊ w 4MBDLCPUͷԼ४උΛ(PͰ؆୯ʹग़དྷΔ w 5ISFBEରԠɺ TMBDL35.TH0QUJPO54 FW5ISFBE5JNFTUBNQ Λऔಘͯ͠͏ ͚ͩ w
4MBDLCPU (P $MPVE'VODUJPOTͷ૬ੑѱ͘ͳ͍ w ࡞Γ͍͢ ֦ுੑ͕͋Δ The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/)
࠷ޙʹ IUUQTHJUIVCDPNLPHVNBHDGMFBTUTMBDLTBNQMFGPS-5
͝੩ௌ͋Γ͕ͱ͏͍͟͝·͠ ͨɻ