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
520
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Go + Google Cloud Functions を使ったSlackのThreadにも対応したbotを簡単に作る方法
Slack Dev Meetup Tokyo #1 LT 資料です。
ktykogm
July 25, 2019
More Decks by ktykogm
See All by ktykogm
AIと新時代を切り拓く。これからのSREとメルカリIBISの挑戦
0gm
3
5.9k
ハイブリッドAIOps・AI Agent戦略:SaaS AI時代のプラットフォームエンジニアリング生存戦略
0gm
1
1.8k
メルカリIBISの紹介
0gm
2
2.9k
メルカリIBIS:AIが拓く次世代インシデント対応
0gm
2
1.8k
街じゅうを"駅前化"する電動マイクロモビリティのシェアサービス「LUUP」のIoTとSRE
0gm
1
11k
サービスと組織の拡大を支えるEmbedded SREs
0gm
7
3.8k
SRE的team開発Tipsとベストプラクティスっぽい何か
0gm
9
5.7k
Other Decks in Programming
See All in Programming
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.6k
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
130
エージェンティックRAGにAWSで入門しよう!
har1101
9
1.9k
Agentic UI
manfredsteyer
PRO
0
220
Dataformのリポジトリを立ち上げるときにまずやること / dataform-day0-2026
snhryt
0
200
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
140
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
8.5k
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
1k
エンジニアと一緒にテストコードの設計と実装を改善した話
mototakatsu
0
240
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
190
スマートグラスで並列バイブコーディング
hyshu
0
270
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
5
760
Featured
See All Featured
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
660
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.2k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
200
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
550
Rebuilding a faster, lazier Slack
samanthasiow
85
9.5k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
180
GraphQLとの向き合い方2022年版
quramy
50
15k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
120k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
180
Building Adaptive Systems
keathley
44
3.1k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
67
56k
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
͝੩ௌ͋Γ͕ͱ͏͍͟͝·͠ ͨɻ