Fork me on GitHub
#fulcro
<
2021-01-17
>
ej10:01:40

This might not be the right place to ask, but does anyone have an idea of the combined AWS costs associated with running an application of the size/complexity as the Fulcro RAD demo with say ... 10-20 concurrect active users per day? I have never used AWS before, but as far as I can understand, I would need to pay for both Datomic Cloud as the DB, and some kind of EC2 instance for the Fulcro application itself. Excuse me if this question is basically "how long is a fish?", or if I should ask it in the datomic channel instead.

tony.kay12:01:08

Fulcro really has no bearing on that. Datomic cloud has a pricing calculator that includes the ec2 and sw charges. You get discounts for dedicated instances, and solo is cheaper than production.

xceno14:01:05

I started with solo but upgraded to prod soon after. I run everything as datomic ion. It costs around 100-200$/month. You can reduce that price a bit by reducing the load balancer to 1 instance, but you obviously loose the redundancy if you do so. However, I didn't have any problems so far. If you're going to use it professionally, I think reserved instances are the way to go. Also, you can host the SPA on S3, but I personally didn't. I'm on my phone right now, but I can provide you some more details later if you have any more questions

❤️ 3
ej17:01:20

Ah, this is very interesting, @U012ADU90SW. I did not know that you could run Fulcro on Datomic Ion. So that means both the database and the server is running there, and you have the frontend running somewhere else? Which EC2 instance type are you running, or do you use one for DB and one for server? On the Datomic price calculator it says they recommend i3.large, which seems a little bit overkill for my needs, but what do I know. :)

xceno23:01:38

Disclaimer... I'm working on a proof of concept with just a hand full of users and the hope to get some funding so we can make a real product out of what I do, so please keep that mind. i3.large is overkill for small projects yes, however after fighting with the initial setup for days (due to missing docs, etc.) I decided to call it a day and switch over to a production setup. With this setup you get the http-gateway which allows for "ionizing" your web-apps. I did this because I'm basically the only dev right now and only have so much time to care for infrastructure stuff - so for me it was essential that i could just "ion-push" a release and let datomic cloud handle everything else for me. To save some costs I changed the autoscale capacity to 1 server. In practice this comes down to 5 minutes of unavailability of my system when you push a new release. As for serving your fulcro SPA: When you look at the RAD demo, making a release build of your frontend will put a bundle in your resources folder, and your ionized ring-handler serves it: https://github.com/fulcrologic/fulcro-rad-demo/blob/datomic-cloud/src/shared/com/example/components/ring_middleware.clj#L30 So to finally answer your question: My backend runs on a single EC2 i3.large instance, talks to my datomic db and serves my Fulcro SPA. You have to extend the RAD authorization system though, or replace it with whatever else you need (AWS cognito for example). I thought about writing a guide to my current setup, but it's not entirely "production ready" and I fear that people will just run with it anyway. But here are some things I found along the way: • https://jacobobryant.com/post/2019/ion/https://github.com/jacobobryant/flexbudgethttps://forum.datomic.com/t/solved-ionize-does-not-handle-responses-with-a-body-of-type-file/1018https://docs.datomic.com/cloud/operation/access-control.html#authorize-ionshttps://theconsultingcto.com/posts/http-direct-with-datomic-and-terraform/

Jakub Holý (HolyJak)08:01:22

The problem with datomic is that the production setup is high-end, which indeed is an overkill for simpler apps. But there is no middle ground between this and solo. Since you already must have the Datomic instance, running Fulcro backend there as an Ion seems the most reasonable. For the frontend, perhaps you can serve if from there or serve it from S3 (perhaps with CloudFront in the front, configured to forward requests for /api to the API Gateway backed by Datomic Ions)

ej09:01:02

Thank you for your detailed responses! This leaves me with a lot of reading to figure out the best approach.

hmaurer21:01:45

@U01FJKR2SEA note that you could also use RAD + a SQL database, if you are not attached to Datomic in particular

hmaurer22:01:10

If you are using a SQL database you could probably get away with a very simple setup of some clojure hosting solution + a managed SQL service

ej22:01:35

@U5ZAJ15P0 I was under the impression that the SQL plugin was kind of a ... second-class citizen in Fulcro, but I am not sure where I got that idea. I am not tied to Datomic in any way right now, as I am just starting out. I have some more reading to do, it seems. Thank you!

hmaurer22:01:37

@U01FJKR2SEA It might be; I wouldn’t be the right person to say (I haven’t used Fulcro in quite a while)! But if you are willing to get your hands dirty I see no reason why you couldn’t get it to work with SQL; it’s just that Datomic is a more natural fit for Pathom & co.

ej22:01:52

Do you have any thoughts on getting started with Fulcro with an SQL database vs Datomic, @U0522TWDA? Is there a big difference? I think ease of learning, support and developer experience is more important to me than cost of deployment (at least right now), but if the difference between the databases is small (abstracted away?) I might prefer the cost-effective solution. If this question seems dumb, it's because I'm just getting started.

Jakub Holý (HolyJak)10:01:31

You can use either just fine. Personally I use a SQL DB. If you want to use RAD - which you should perhaps avoid until you get familiar with Fulcro itself - then you must know that the SQL adapter is much less developed so auto-generated resolvers and form save middleware might not work always for you. I write all my resolvers manually so for me it is not a problem.

👍 3
Henry13:01:27

In the following code, People is the root. People has a list of Persons. Each Person has an address. I have a quick question: Is it possible to auto normalise the data in the Person component not only with :person/id, but also with :address/id? I understand that there can only be one ident in each component for auto-normalisation to work. However, nesting address to person in this way seems cumbersome and inefficient. I thought about creating an Address component, but then each person would have the same address (or same many addresses if it is to-many). What would be the best way to approach the design of data structure in this scenario? Thanks a lot for helping.

daniel.spaniel13:01:59

Henry, normally you would do an Address component and then use a join in the address part of person query {:person/address (prim/get-query Address)]}

daniel.spaniel13:01:15

not sure why you don't want to do that, since this normalizes address and will take care of duplicates

Henry13:01:27

Yes, that's what I thought too, but as I mentioned, I am trying to wrap my mind around this: wouldn't an Address component give every person the same address?

daniel.spaniel13:01:54

no, just try it and see

Henry14:01:18

Thanks @dansudol for your help. I added the Address component but the question was still unresolved. Therefore, I used merge-component! to check, and you're right, the data structure worked well. I then realised that my question actually pertained to the initial-state. For now, both [:person/id 1] and [:person/id 2] have [:address/id 1]. How can you for example add [:address/id 2] to [:person/id 2] in the initial-state?

Jakub Holý (HolyJak)08:01:31

FYI it is preferable to use the https://book.fulcrologic.com/#_template_mode - it is simpler and has some error checking

Jakub Holý (HolyJak)08:01:13

When saying "the same address" did you mean the last line in

:initial-state (fn [{:keys [id name]}] {:person/id      id
                                           :person/name    name
                                           :person/address (comp/get-initial-state Address
                                                             {:id 1 :street "Sweet Street"})})}
? You can pass to this initial state also params for the address, nothing stops you from that. In the template form:
:initial-state {:person/id      :param/id                                      :person/name    :param/name                                           :person/address {:id :param/address-id 1 :param/address-street "Sweet Street"}})}
Though of course in practice you don't need complex state initialization in init state b/c you load the data from a server. Or use the lambda form and return some random data. Depending on what you need.

daniel.spaniel16:01:13

gee .. i don't know .. maybe in the Person component in the initial-state fn instead of just keys for id and name .. add address and then pass in the same address over and over again. and you could define the address map as a def sweet-street and then reuse it

👹 3